hdu2819 swap(二分图匹配)

Description

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”. 

题意:给出一个0/1矩阵,问是否可以通过不断交换两行或两列得到一个左上右下对角线全是1的矩阵。如果可以,输出任意方案。(R a b交换a,b两行,C a b交换a,b两列)。有special judge,要求步骤数小于1000。

这题我一开始根本不觉得这和二分图有什么关系。。这几天搜索题做多了,第一反应是构造h函数。。然而这题确实巧妙。你可以先假定有一个主对角线全是1其他全是0的矩阵,然后乱交换几次看看,就有规律了:无论交换哪两行或者两列,得到的都是一个置换矩阵(每行每列仅一个1)。那么问题就显然是求原矩阵中是否包含一个置换矩阵。由于每行每列仅一个一,就将原图中所有行作为X部,列作为Y部,对矩阵中每个1将其行和列连边,检查是否满流即可。

至于输出方案,将那个置换矩阵取出来,再模拟一次给所有1的y坐标升序排序的过程即可。为了让交换次数尽量少,建议手写选择排序。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 250
#define MAXM 51000
int N, M, cnt;
int mat[MAXN][MAXN];

struct Node { int to; Node*next; };
struct BiGraph {
    int match[MAXN], xn;
    bool vis[MAXN];
    Node Edge[MAXM*2], *ecnt, *adj[MAXN];
    BiGraph() { memset(adj,0,sizeof adj); ecnt=Edge; }
    void addedge(int a, int b)
    {
		++ecnt;
		ecnt->to = b;
		ecnt->next = adj[a];
		adj[a] = ecnt;
    }
    bool dfs(int u)
    {
		for (Node*p = adj[u]; p; p=p->next) {
			int &v = p->to;
			if (vis[v]) continue;
			vis[v] = 1;
			if (!match[v] || dfs(match[v])) {
				match[u] = v; match[v] = u;
                return 1;
			}
		}
		return 0;
    }
    int Maxmatch()
    {
		int ans = 0;
		for (int i = 1; i<=xn; ++i)
			if (!match[i]) {
				memset(vis, 0, sizeof vis);
				ans += dfs(i);
			}
		return ans;
	}
} Empty, G;

int a[MAXN];
int x1[1000], x2[1000];
int main()
{
	int i, j;
	while (~scanf("%d", &N)) {
		G = Empty;
		G.xn = N;
		M = cnt = 0;
		for (i = 1; i<=N; ++i)
			for (j = 1; j<=N; ++j) {
				scanf("%d", &mat[i][j]);
				if (mat[i][j])
					G.addedge(i, j+N);
			}
		if (G.Maxmatch() < N) {
			puts("-1");
			continue;
		}
		for (i = 1; i<=N; ++i)
			for (j = 1; j<=N; ++j)
				if (mat[i][j] && G.match[i]==j+N)
					a[++cnt] = j;
		for (i = 1; i<=N; ++i) {
			if (a[i] == i) continue;
			for (j = i; j<=N; ++j)
				if (a[j] == i) {
					swap(a[i], a[j]);
					++M;
					x1[M] = i; x2[M] = j;
					break;
				}
		}
		printf("%d\n", M);
		for (i = 1; i<=M; ++i)
			printf("R %d %d\n", x1[i], x2[i]);
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值