题意:n*n的格子,每行和每列都是1~n的每个数出现一次。给出前k行,补全剩下的n-k行。1<=n<=100,0<k<=n.
题解:二分匹配裸题。
1.假如第i行有100种填写方法,那么每一种均可,不会出现第p种填写方案使后面行无法填写而第q种填写方案使后面行可以填写的情况。
2.逐行匹配即可。
#include<bits/stdc++.h> #define N 105 using namespace std ; int n , m ; int a[N][N] ; int match[N] ; bool vis[N] ; bool used[N][N] ; bool dfs(int x) { int i , j ; for(i = 1 ; i <= n ; i ++) { if(!used[x][i] && !vis[i]) { vis[i] = 1 ; if(match[i] == -1 || dfs(match[i])) { match[i] = x ; return 1 ; } } } return 0 ; } bool judge_row() { int i , j ; bool vis1[N] ; for(i = 1 ; i <= n ; i ++) { memset(vis1 , 0 , sizeof(vis1)) ; for(j = 1 ; j <= n ; j ++) vis1[a[i][j]] = 1 ; for(j = 1 ; j <= n ; j ++) if(!vis1[j]) return 0 ; } return 1 ; } bool judge_col() { int i , j ; bool vis1[N] ; for(j = 1 ; j <= n ; j ++) { memset(vis1 , 0 , sizeof(vis1)) ; for(i = 1 ; i <= n ; i ++) vis1[a[i][j]] = 1 ; for(i = 1 ; i <= n ; i ++) if(!vis1[i]) return 0 ; } return 1 ; } int main() { int i , j ; int ans ; bool flag = 1 ; memset(used , 0 , sizeof(used)) ; scanf("%d%d" , &n , &m) ; for(i = 1 ; i <= m ; i ++) for(j = 1 ; j <= n ; j ++) { scanf("%d" , &a[i][j]) ; used[j][a[i][j]] = 1 ; } for(i = m + 1 ; i <= n ; i ++) { ans = 0 ; memset(match , -1 , sizeof(match)) ; for(j = 1 ; j <= n ; j ++) { memset(vis , 0 , sizeof(vis)) ; if(dfs(j)) ans ++ ; } if(ans < n) { flag = 0 ; break ; } for(j = 1 ; j <= n ; j ++) a[i][match[j]] = j ; for(j = 1 ; j <= n ; j ++) used[j][a[i][j]] = 1 ; } if(!judge_row() || !judge_col()) flag = 0 ; if(flag == 0) printf("no") ; else { printf("yes\n") ; for(i = 1 ; i <= n - 1 ; i ++) { for(j = 1 ; j <= n - 1 ; j ++) printf("%d " , a[i][j]) ; printf("%d\n" , a[i][n]) ; } for(j = 1 ; j <= n - 1 ; j ++) printf("%d " , a[n][j]) ; printf("%d" , a[n][n]) ; } }
