Superdoku Kattis - superdoku (二分图匹配)
题目链接:
L - Superdoku
Kattis - superdoku
题目大意:给你一个n*n的矩阵,给你这个矩阵的前k行,问你是否能构成矩阵使得每一行每一列都是1~n的排列。
具体思路:首先我们记录每一行,每一列都有哪些数存在,然后从第k+1行开始,每一次就是1~n对(当前列中没有的数)的匹配,然后一共匹配1-n就可以了,逐行判断就可以了。
注意这里的net数组储存的是当前net[i],数字i指向的是哪一行,所以我们需要再开一个映射数组,当前行储存的是哪个数字。
AC代码:
1 #include<bits/stdc++.h>
2 using namespace std;
3 # define ll long long
4 const int maxn = 2e5 + 100;
5 const int N = 150;
6 int a[N][N];
7 int H[N][N],L[N][N];
8 int net[N],vis[N];
9 int ans[N];
10 bool Find(int pos,int n)
11 {
12 for(int i=1; i<=n; i++)
13 {
14 if(L[pos][i]||vis[i])
15 continue;
16 vis[i]=1;
17 if(net[i]==0||Find(net[i],n))
18 {
19 net[i]=pos;
20 ans[pos]=i;
21 return true;
22 }
23 }
24 return false;
25 }
26 bool match(int pos,int n)
27 {
28 memset(net,0,sizeof(net));
29 int num=0;
30 for(int i=1; i<=n; i++)
31 {
32 memset(vis,0,sizeof(vis));
33 if(Find(i,n))
34 num++;
35 }
36 return num==n;
37 }
38 bool solve(int n,int k)
39 {
40 int num=0;
41 for(int i=k+1; i<=n; i++)
42 {
43 if(match(i,n))
44 num++;
45 for(int j=1; j<=n; j++)
46 {
47 a[i][j]=ans[j];
48 H[i][ans[j]]=1;
49 L[j][ans[j]]=1;
50 }
51 }
52 return num==n-k;
53 }
54 int main()
55 {
56 int n,k;
57 int flag=1;
58 scanf("%d %d",&n,&k);
59 for(int i=1; i<=k; i++)
60 {
61 for(int j=1; j<=n; j++)
62 {
63 scanf("%d",&a[i][j]);
64 if(++H[i][a[i][j]]>2)
65 flag=0;
66 if(++L[j][a[i][j]]>2)
67 flag=0;
68 }
69 }
70 if(!flag)
71 printf("no\n");
72 else
73 {
74 if(k==0)
75 {
76 for(int i=1; i<=n; i++)
77 {
78 a[1][i]=i;
79 H[1][i]=1;
80 L[i][i]=1;
81 }
82 k=1;
83 }
84 if(!solve(n,k))
85 printf("no\n");
86 else
87 {
88 printf("yes\n");
89 for(int i=1; i<=n; i++)
90 {
91 for(int j=1; j<=n; j++)
92 {
93 if(j==1)
94 printf("%d",a[i][j]);
95 else
96 printf(" %d",a[i][j]);
97 }
98 printf("\n");
99 }
100 }
101 }
102 return 0;
103 }