Swap HDU - 2819 (二分图最大匹配+路径还原)

Swap

HDU - 2819

Given an N*N matrix with each entry equal to 0 or 1. You can swap any two rows or any two columns. Can you find a way to make all the diagonal entries equal to 1?

Input There are several test cases in the input. The first line of each test case is an integer N (1 <= N <= 100). Then N lines follow, each contains N numbers (0 or 1), separating by space, indicating the N*N matrix. Output For each test case, the first line contain the number of swaps M. Then M lines follow, whose format is “R a b” or “C a b”, indicating swapping the row a and row b, or swapping the column a and column b. (1 <= a, b <= N). Any correct answer will be accepted, but M should be more than 1000.

If it is impossible to make all the diagonal entries equal to 1, output only one one containing “-1”.
Sample Input
2
0 1
1 0
2
1 0
1 0
Sample Output
1
R 1 2
-1

详细解释

我在代码中又具体解释了下路径输出的过程、

code:

#include 
#include 
#include 
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 105
bool G[MAXN][MAXN],vis[MAXN];
int match[MAXN],N,M,T,a[MAXN],b[MAXN];

bool dfs(int u){
	int i;
	for(i = 0; i <= N; i++){
		if(G[u][i] && !vis[i]){
			vis[i] = true;
			if(!match[i] || dfs(match[i])){
				match[i] = u;
				return true;
			}
		}
	}
	return false;
}
int main(){
	while(~scanf("%d",&N)){
		memset(G,0,sizeof(G));
		memset(match,0,sizeof(match));
		int x,ans = 0;
		int i,j;
		for(i = 1; i <= N; i++){
			for(j = 1; j <= N; j++){
				scanf("%d",&x);
				if(x)
				  G[i][j] = true;
			}
		}
		for(i = 1; i <= N; i++){
			memset(vis,0,sizeof(vis));
			if(dfs(i))
			  ans++;
		}
		//上面代码就是简单的求最大二分匹配的模板
		 
		if(ans < N){//如果最大二分匹配小于N,则说明矩阵的秩不是N,一定无法达到要求 
			printf("-1\n");
			continue;
		}
		//以下是路径还原 
		int tot = 0;
		//就目前来说,我们通过二分图最大匹配得到的match匹配数组只是证明这个矩阵的秩是n,可以通过
		//交换得到,对角线都是1,并且已经记录下了匹配(即谁和谁进行交换),但是还没有进行交换
		//实际上下面的任务只是根据match数组给我们指令,进行模拟交换一下就可以了,顺便记录下每次是
		//谁和谁交换的即可 
		for(i = 1; i <= N; i++){//每个点都当做一个起点 (行号i) 
			for(j = 1; j <= N && match[j] != i; j++);//找到与之匹配的那个点(列号j)match[j]=i就是将j列的1移动到i列得到G[i][i]=1,完成一次交换 
			
			if(i != j){//只有当ij不相等才需要交换,如果相等说明原来这个点就在对角线上不用交换了 
				a[tot] = i;
				b[tot] = j;//记录下交换的路径 
				tot++;
				//交换完了,那就要真的交换过来,只需要交换match数组即可,就实现的j列和i列的交换,即j列现在对应了原来i列所对应的行号i',反之亦然 
				int t = match[i];
				match[i] = match[j];
				match[j] = t;
			}
			
		}
		printf("%d\n",tot);
		for(i = 0; i < tot; i++)
		   printf("C %d %d\n",a[i],b[i]);
		//cout << "----------------------------------------------" << endl;
	}
	return 0;
}


你可能感兴趣的:(二分图)