Swap HDU - 2819
考察:二分图匹配+线性代数(?)
完全是参考大佬的思路:
根据线性代数的知识,如果矩阵的对角线全为1,说明该矩阵的秩是满的,而初等变换(交换行或者列)不改变矩阵的秩,因此行变换可由列变换代替,其实这道题感觉是在求矩阵的秩,行列变换同时进行会改变矩阵的秩,因此这道题只用行变换或者列变换即可
关键是如何建立二分图:
根据前面的题很容易想到是横坐标一个集合,纵坐标一个集合.我们要求每一行上都有1,也就是把第i行的1交换到第i列.因此两集合的关系就出来了,将i行指向该行的所有1,边的意义就是将该行的1换到第i列.
关于最后交换swap:
我们找到与i匹配的match[j]后,实际上是交换了第j列和第i列.原来指向第j列的也要发生改变.实在不能理解可在纸上模拟
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <set> 5 using namespace std; 6 typedef pair<int,int> pii; 7 const int N = 110; 8 int match[N*N],n,mp[N][N]; 9 bool st[N*N],g[N][N]; 10 set<pii> s; 11 void inits() 12 { 13 memset(match,0,sizeof match); 14 memset(g,0,sizeof g); s.clear(); 15 } 16 bool dfs(int x) 17 { 18 for(int i=1;i<=n;i++) 19 { 20 if(!g[x][i]||st[i]) continue; 21 st[i] = 1; 22 if(!match[i]||dfs(match[i])) 23 { 24 match[i] = x; 25 return true; 26 } 27 } 28 return false; 29 } 30 int main() 31 { 32 // freopen("in.txt","r",stdin); 33 while(scanf("%d",&n)!=EOF) 34 { 35 inits(); 36 int res = 0; 37 for(int i=1;i<=n;i++) 38 for(int j=1;j<=n;j++) 39 { 40 scanf("%d",&mp[i][j]); 41 if(mp[i][j]) g[i][j] = 1; 42 } 43 for(int i=1;i<=n;i++) 44 { 45 memset(st,0,sizeof st); 46 if(dfs(i)) res++; 47 } 48 if(res!=n) puts("-1"); 49 else{ 50 for(int i=1;i<=n;i++) 51 if(match[i]!=i) 52 { 53 for(int j=1;j<=n;j++) 54 { 55 if(i==match[j]) 56 { 57 s.insert({i,j}); 58 swap(match[i],match[j]);//原来的第i列变成了第j列 59 } 60 } 61 } 62 printf("%d\n",s.size()); 63 for(auto it=s.begin();it!=s.end();it++) printf("C %d %d\n",it->first,it->second); 64 } 65 } 66 return 0; 67 }