题意:通过交换行或者列来实现对角线(左上角到右下角)上都是1,
首先,如果某行全是0或者某列全是0必然不满足情况输出-1,如果能转换的话,那么必然可以通过全由行(列)变换得到;
还有就是对角线上的N个1,它们各自在不同的行中出现至少一次才可以,
比如样例2中,虽然有两个1,但是它们总是处在同一列,仍然不满足要求,
很明显不能一个行对应两个列,或者说,每一行都应该有至少一个与自己对应的列才能满足条件;
那么将行作为X集合,列作为Y集合,如果map[i][j]==1,那么Xi->Yj连边,求最大匹配,这样的话没有任何一个行被两个列匹配,也就满足了我们的要求,
如果最大匹配==N,那么必然有解,否则必然无解;
#include<stdio.h> #include<string.h> #include<algorithm> #include<vector> #include<queue> #include<string> #include<stack> #include<map> using namespace std; #define N 1100 #define INF 0x3f3f3f3f #define met(a, b) memset(a, b, sizeof(a)) int used[N], G[N][N], vis[N], n; int Find(int u) { for(int i=1; i<=n; i++) { if(!vis[i] && G[u][i]) { vis[i] = 1; if(!used[i] || Find(used[i])) { used[i] = u; return 1; } } } return 0; } int main() { while(scanf("%d", &n) != EOF) { met(G, 0); for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { int op; scanf("%d", &op); G[i][j] = op; } } int ans = 0; met(used, 0); for(int i=1; i<=n; i++) { met(vis, 0); ans += Find(i); } if(ans < n) { printf("-1 "); continue; } int cnt = 0, a[N]={0}, b[N]={0}; ///相当于是给一个数组used排序的过程,使得交换的次数最少; ///每次把i位置上的数,放到应该放的位置,直到当前位置是对应的数为止; for(int i=1; i<=n; i++) { while(i != used[i]) { a[cnt] = i; b[cnt] = used[i]; swap(used[i], used[used[i]]); cnt ++; } } printf("%d ", cnt); for(int i=0; i<cnt; i++) printf("C %d %d ", a[i], b[i]); } return 0; } /* 3 0 1 1 0 0 1 1 0 0 */