HDU-2819 Swap(二分图最大匹配,路径记录)
题意:给你一个0,1的矩阵然后你现在可以多次交换任意的两行或者两列
使得该矩阵的对角线全为1.如果不能则输出-1
思路:我们可以把行列交换看做一种匹配,要是得对角线的所有为1
就要把所有的1交换到G[i][i]的位置,比如某个1在(0,1){初始行号为0}
那么我们就可以把它交换到(0,0)或者(1,1),即交换到行号相同或者列号相同的位置
同时题中要求的交换是得到的最终位置,而不是交换过程中的位置
所以对于每一个行i都要进行匹配一次,就转换成了最大匹配问题
当然记录路径我们可以是换行也可以是换列
完整代码:
#include <algorithm> #include <iostream> #include <cstdio> #include <cstring> using namespace std; int G[105][105]; int n; struct Path { int x,y; }path[1000]; int match[105]; int vis[105]; int cnt,ans; bool Find(int u){ for(int i = 1;i<=n;i++){ if(!vis[i]&&G[u][i]){ vis[i] = 1; if(!match[i]||Find(match[i])){ match[i] = u;//这里的match是列对行的匹配 return true; } } } return false; } void printPath(){ int tmp; for(int i = 1;i<=n;i++){ if(match[i]!=i){ for(int j =i;j<=n;j++){ if(match[j]==i){ path[cnt].x = i; path[cnt++].y = j; tmp = match[i]; match[i] = match[j]; match[j] = tmp;//表示列被交换 } } } } } int Count(){ int count = 0; memset(match,0,sizeof(match)); for(int i =0;i<=n;i++){ memset(vis,0,sizeof(vis)); if(Find(i)) count++; } return count; } int main(){ while(cin>>n){ for(int i = 1;i <= n; i++){ for(int j = 1; j <= n; j++){ cin>>G[i][j]; } } ans = cnt = 0; if(Count()!=n) cout<<-1<<endl; else{ printPath(); cout<<cnt<<endl; for(int i=0;i<cnt;i++){ printf("C %d %d\n",path[i].x,path[i].y); } } } return 0; }