hdu - 2819 Swap 二分图匹配

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

Sample Input
2
0 1
1 0
2
1 0
1 0

Sample Output
1
R 1 2
-1

题目问是否能通过交换行列,使得01矩阵对角线上的所有元素都为1。
因为我们只关注对角线上的值,很容易想到交换列的结果能通过交换行来实现,交换行的结果也能通过交换列来实现。下面以交换行为例。
首先我们先判断是否每一列上都有1,如果不能保证这一条件,则无论如何交换行都无法实现,同时进行匹配过程,得到每一列所在行的位置。
为什么要用二分图匹配去求呢?假设maps[1][1] == 1,maps[1][2] == 1,但是这只能满足一行的条件,那么我们这时选第一行匹配了第一列还是第二列呢?这得看其他行的情况。假设maps[2][1] == 0,maps[2][2] == 1,那么第二行只能匹配第二列,此时第一行就要匹配第一列。这个过程就是二分图匹配的过程。
然后就可以进行暴力遍历,找每一行对应的点的匹配的值是否与其相同,如果不相同,则去寻找与其相同的点,用交换他们的匹配值来代表交换了行。

#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
#define N 510
int vis[N], used[N], maps[N][N], n, ans;
vector<pair<int,int>>G;
bool Find(int u){
    for(int i=1; i<=n; i++){
        if(!vis[i] && maps[i][u]){
        //因为读的时候读的是行与列的关系,所以这里遍历数组的第一维来找列与行的关系
            vis[i] = 1;
            if(!used[i] || Find(used[i])){
                used[i] = u;
                return true;
            }
        }
    }
    return false;
}
int main(){
    int a, b, m, t; 
	while(~scanf("%d", &n)){
        memset(maps, 0, sizeof(maps));
        for(int i=1; i<=n; ++i)
        	for(int j=1;j<=n; ++j)
            scanf("%d", &maps[i][j]);
        ans = 0;
        memset(used, 0, sizeof(used));
        for(int i=1; i<=n; i++){
            memset(vis, 0, sizeof(vis));
            if(Find(i))
                ans++;
        }
        if(ans != n){
        	puts("-1");
        	continue;
		}
		G.clear();
		int num=0;
		for(int i=1;i<=n;++i){
			if(used[i] != i){
				num++;
				for(int j=i + 1;j<=n;++j){
					if(used[j] == i){
						G.push_back({i,j});//记录交换情况
						swap(used[j],used[i]);
						break;
					}
				}
			}
		}
		printf("%d\n",num);
		for(int i=0;i<num;++i){
			printf("R %d %d\n",G[i].first,G[i].second);
		}
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值