BZOJ1059 ZJOI2007 矩阵游戏 二分图
题意:给定一个N*M的网格,每个格子均为白色或黑色,每次可以交换两行或两列,求是否可以通过有限次操作使得从左上到右下的对角线上所有的格子均为黑色
题解:首先,同一列上的格子无论怎么变换都在同一列上,同一行上的格子无论怎么变换都在同一行上,因此问题转化为求既不在同一列也不在同一行上的黑色格子的数量与N的关系。我们建二分图,左边一列为行,右边一列为列,如果(x,y)是黑色则在左边的x和右边的y之间连边,然后跑二分图最大匹配。
#include <queue> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=500+2; struct HASH{ int u; HASH *next; HASH(){} HASH(int _u,HASH *_next):u(_u),next(_next){} }*table[MAXN],mem[MAXN*MAXN]; int N,T,cnt,dx[MAXN],dy[MAXN],mx[MAXN],my[MAXN]; queue<int> q; void Insert(int u,int v){ table[u]=&(mem[cnt++]=HASH(v,table[u]));} bool BFS(){ memset(dx,0,sizeof(dx)); memset(dy,0,sizeof(dy)); for(int i=1;i<=N;i++) if(mx[i]==-1) q.push(i); int x; bool flag=0; while(!q.empty()){ x=q.front(),q.pop(); for(HASH *p=table[x];p;p=p->next) if(!dy[p->u]){ dy[p->u]=dx[x]+1; if(my[p->u]==-1) flag=1; else dx[my[p->u]]=dy[p->u]+1,q.push(my[p->u]); } } return flag; } bool DFS(int x){ for(HASH *p=table[x];p;p=p->next) if(dy[p->u]==dx[x]+1){ dy[p->u]=0; if(my[p->u]==-1 || DFS(my[p->u])){ mx[x]=p->u,my[p->u]=x; return 1; } } return 0; } bool Hopcroft_Karp(){ int ret=0; memset(mx,-1,sizeof(mx)); memset(my,-1,sizeof(my)); while(BFS()) for(int i=1;i<=N;i++) if(mx[i]==-1 && DFS(i)) ret++; return ret==N; } int main(){ scanf("%d",&T); while(T--){ cnt=0; memset(table,0,sizeof(table)); scanf("%d",&N); for(int i=1,c;i<=N;i++) for(int j=1;j<=N;j++){ scanf("%d",&c); if(c) Insert(i,N+j); } if(Hopcroft_Karp()) cout << "Yes" << endl; else cout << "No" << endl; } return 0; }