分析:看到这题呢,首先想到的就是搜索,数据范围也不大嘛。但是仔细思考发现这题用搜索很难做,看了大佬们的题解后学到了,这一类题目要用二分图匹配来做。可以知道,如果想要的话,每一个子都可以移动到任意位置(当然会对其他子造成影响),我们还可以发现,每一行或每一列有哪些子其实绝对是固定的,只是它们之间的相对顺序会改变。
瞎扯了这么多,进入正题吧,首先如果a[i][j]是黑子,那么我们想要得到的目标当然是把它移动到a[i][i],那么他当前的位置就可以看作j,目标位置是i,那么就把j和i之间连一条边,将所有边连接以后发现这其实是个二分图,那么就二分图匹配啊,如果能满足有n个匹配那么就说明目标状态可以达到(这个应该不难想吧)。所以建边以后直接匈牙利算法就OK了。(PS:补充一句,建边的时候别忘了把数组开大点,一开始脑子有洞忘了,结果RE得非常感人......)
Code:
1 //It is made by HolseLee on 3rd Apr 2018 2 //Luogu.org P1129 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<cmath> 7 #include<iostream> 8 #include<iomanip> 9 #include<algorithm> 10 const int N=201; 11 int T,n; 12 int a[N][N],match[N]; 13 int head[N],size; 14 bool vis[N]; 15 struct Node{ 16 int to,next; 17 }edge[50005]; 18 inline int read() 19 { 20 char ch=getchar();int num=0;bool flag=false; 21 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)flag=true;ch=getchar();} 22 while(ch>=‘0‘&&ch<=‘9‘){num=num*10+ch-‘0‘;ch=getchar();} 23 return flag?-num:num; 24 } 25 inline void ready() 26 { 27 size=0; 28 memset(head,-1,sizeof(head)); 29 memset(match,-1,sizeof(match)); 30 memset(vis,false,sizeof(vis)); 31 } 32 inline void add(int x,int y) 33 { 34 edge[++size].to=y; 35 edge[size].next=head[x]; 36 head[x]=size; 37 } 38 inline bool dfs(int x) 39 { 40 for(int i=head[x];i!=-1;i=edge[i].next){ 41 int y=edge[i].to; 42 if(vis[y])continue; 43 vis[y]=true; 44 if(match[y]==-1||dfs(match[y])){ 45 match[y]=x; 46 return true;}} 47 return false; 48 } 49 inline void work() 50 { 51 n=read(); 52 for(int i=1;i<=n;i++) 53 for(int j=1;j<=n;j++) 54 a[i][j]=read(); 55 for(int i=1;i<=n;i++) 56 for(int j=1;j<=n;j++) 57 if(a[i][j])add(j,i); 58 for(int i=1;i<=n;i++){ 59 memset(vis,false,sizeof(vis)); 60 if(!dfs(i)){printf("No\n");return;}} 61 printf("Yes\n"); 62 } 63 int main() 64 { 65 T=read(); 66 while(T--){ 67 ready(); 68 work();} 69 return 0; 70 }