[bzoj]1059矩阵游戏<二分图匹配*匈牙利算法>
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1059
初见此题,我觉得这是水题,我认为只要每一行和每一列至少存在一个黑格就可以出现对角线,但是在一位名叫*ZJ的AK大佬用一张图点醒我后,我幡然醒悟
就是这张图,因为这图的每一列和每一行都至少含一个黑格,但是这张图无论怎么样操作都得不到对角线,然后在这位大佬的进一步提醒下,我尝试了二分图匹配算法
能够分析此图,我将黑格坐标的x,y连边,可以得到这张图
从二分图匹配角度看,无论如何它都无法成为一个完美匹配,而要使最后出现对角线,必须要出现完美匹配,及每一个点都要匹配成功(这是一个结论,画几个图即可推出)
我们来举一个成功例子
右图是黑格位置,左图是二分图匹配的连边情况,我们可以看出,这个二分图匹配能够成为一个完美匹配,也可以从图上分享知道这张图可以通过一次列的交换操作完成对角线
这就是此题的思路,完美匹配就简单的用匈牙利算法就行
然后还是让我们看看代码
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #define maxn 205 8 using namespace std; 9 10 struct edge{ 11 int u,v,w,nxt; 12 }e[maxn*maxn]; 13 14 int n,m,t,head[maxn],vis[maxn],att[maxn],ans; 15 16 int k=1; 17 void adde(int u,int v){ 18 e[k].u=u; 19 e[k].v=v; 20 e[k].nxt=head[u]; 21 head[u]=k++; 22 } 23 24 int can(int x) 25 { 26 for(int i=head[x];i;i=e[i].nxt) 27 { 28 int v=e[i].v; 29 if(vis[v]==0) 30 { 31 vis[v]=1; 32 if(att[v]==0||can(att[v])) 33 { 34 att[v]=x; 35 return 1; 36 } 37 } 38 39 } 40 return 0; 41 } 42 43 int main() 44 { 45 scanf("%d",&t); 46 while(t--) 47 { 48 ans=0;k=1; 49 memset(att,0,sizeof(att)); 50 memset(head,0,sizeof(head)); 51 scanf("%d",&n); 52 for(int i=1;i<=n;i++) 53 for(int j=1;j<=n;j++) 54 { 55 int a; 56 scanf("%d",&a); 57 if(a==1){ 58 adde(i,j);//黑格坐标i,j连边 59 } 60 } 61 for(int i=1;i<=n;i++) 62 { 63 memset(vis,0,sizeof(vis)); 64 if(can(i))ans++; 65 } 66 if(ans==n){ 67 printf("Yes\n"); 68 }else{ 69 printf("No\n"); 70 } 71 72 73 } 74 }