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 <iostream>
#include <cstring>
#include <cstdio>
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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 给出一个由 $n$ 个数排成的序列,你可以进行如下操作: 交换相邻的两个数。 将该序列中的第 $k$ 个数改为 $x$。 你的任务是将该序列变成一个等差数列。 输入格式 第一行包含两个整数 $n$ 和 $m$,表示序列长度和操作次数。 第二行包含 $n$ 个整数,表示初始序列。 接下来 $m$ 行,每行描述一个操作,格式如下: 1. swap x y:表示交换原序列中下标为 $x$ 和 $y$ 的数。 2. set x y:表示将原序列中下标为 $x$ 的数修改为 $y$。 输出格式 如果无法将序列变成等差数列,输出 Impossible。 否则,第一行输出 Yes。 第二行输出变换后的序列。 数据范围 $1 \leq n \leq 5000$ $1 \leq m \leq 10^5$ $1 \leq |a_i|, |x|, |y| \leq 10^9$ 输入样例1: 5 3 5 4 3 2 1 set 2 6 swap 1 2 set 4 1 输出样例1: Yes 6 4 3 1 2 输入样例2: 5 3 5 4 3 2 1 set 2 6 swap 1 2 set 4 10 输出样例2: Impossible 算法1 (二分图匹配) $O(n^3)$ 由于每次可以交换相邻的两个数,可以通过这个操作来使序列中的某个数字移动到另一个位置,因此可以考虑每个数字在序列中的位置之间建立一条边,如果两个数字之间可以通过交换相邻数变成等差数列,则在它们之间连一条边。 具体而言,如果有两个数字 $a,b$,假设它们当前的位置分别为 $i,j$,那么它们之间就可以连一条边,如果它们能够使得序列变成等差数列。 对于 $set$ 操作,可以考虑将该位置对应的点与其他点之间的边全部删除,然后重新建立连接。 最后,判断是否存在一个匹配,使得所有点都与另一个点进行匹配,如果存在,则说明可以通过交换相邻数的方式使得序列变成等差数列。 时间复杂度 - 建图 $O(n^2)$ - 匈牙利算法 $O(n^3)$ C++ 代码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值