BZOJ 1059(二分圖匹配)
阿新 • • 發佈:2018-12-29
題面
分析
遊戲的操作有以下性質:
1.如果兩個格子在同一列,那麼無論如何操作,這兩個格子都在同一列。
2.如果兩個格子在同一行,那麼無論如何操作,這兩個格子都在同一行。
3.可以通過操作改變改點在對應行和列中的位置。
我們發現對於第i行,我們必須要找到某一列上的黑格子挪過來放在對角線上,相當於每一行必須和每一列一一對應
所以對於黑格子(i,j),我們將i向j連邊,跑二分圖匹配
如果答案為n則有解,否則無解
程式碼
#include<iostream> #include<cstdio> #include<cstring> #define maxm 100005 #define maxn 100005 using namespace std; int t,n; struct edge{ int from; int to; int next; }E[maxm]; int head[maxn]; int sz=0; void add_edge(int u,int v){ // printf("%d %d\n",u,v); sz++; E[sz].from=u; E[sz].to=v; E[sz].next=head[u]; head[u]=sz; } int vis[maxn]; int match[maxn]; int dfs(int x,int t){ for(int i=head[x];i;i=E[i].next){ int y=E[i].to; if(vis[y]<t){ vis[y]=t; if(!match[y]||dfs(match[y],t)){ match[y]=x; return 1; } } } return 0; } int hungary(){ memset(vis,0,sizeof(vis)); memset(match,0,sizeof(match)); int ans=0; for(int i=1;i<=n*2;i++){ if(dfs(i,i)) ans++; else break; } return ans; } void ini(){ sz=0; memset(E,0,sizeof(E)); memset(head,0,sizeof(head)); } int main(){ int x; scanf("%d",&t); for(int cas=1;cas<=t;cas++){ scanf("%d",&n); ini(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&x); if(x==1) add_edge(i,j+n); } } if(hungary()==n) printf("Yes\n"); else printf("No\n"); } }