Swap 二分匹配

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

给一个矩阵,判断是否能通过交换行或者列,使这个矩阵的对角线(主对角线)上的元素都为1。如果能,那么给出交换的顺序。
这个题最开始我是想用线性代数来解,化成单位阵,判断矩阵有没有逆不就完事了。但是算行列式数据给的太大了,然后,就没有然后了。
之后,根据题意,在对角线位置上换个一出来1出来,那就先找到这一列中那几行有1,答案必定在几行里。如果将每一行和列都抽象成一个点,那么不久成了一个二分图匹配的问题了么。
综上,现在对矩阵的判断转换成了求二分图的最大匹配,根据最大匹配数来判断是否能构成单位阵。如果能,再考虑交换顺序的给出。
根据线性代数中的知识,一个初等阵一定可以仅通过行变换或者仅通过列变换化为初等阵。所以在交换时,可以只考虑交换行或者交换列,在这里以交换行为例。
运行匈牙利算法之后,可以在match数组中找到匹配关系,也就是 对于第 i 列选择第 match[i] 行交换到第 i 行。注意的是,match[i]中行的序号始终是对原矩阵而言,不随交换而发生变化。比如第1行要与 match[1]:4 行交换,这样现在的第1行就是原矩阵的第4行,原矩阵的第1行现在位于第4行;之后第2行要与 match[2]:1 行交换,这里的第1行是原矩阵的第1行,就是现矩阵的第4行。
所以要建立一个映射关系:原矩阵的第 i 行位于现矩阵的第 pos[i] 行,并在交换的时候正确的修正这个映射。


#include <stdio.h>
#include <climits>
#include <cstring>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <utility>
#include <vector>
#include <string>

#define colStar 105
#define MAXN 210
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return

#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;

bool used[MAXN];
int match[MAXN];
int pos[MAXN];
int store[105][105];
vector<int> adj[MAXN];
bool dfs(int v);
int main(){
    ios::sync_with_stdio(false);

    int n;
    while(cin>>n){
        rep(i,1,n+1){
            rep(j,1,n+1)
                cin>>store[i][j];
        }

        //recode
        rep(i,1,n+1){
            rep(j,1,n+1){
                if(store[j][i]){
                    adj[colStar+i].Push(j);
                }
            }
        }

        int peak=0;
        memset(match,-1,sizeof(match));
        rep(i,1,n+1){
            int v=i+colStar;
            if(adj[v].size()>0 && match[v]<0){
                memset(used,false,sizeof(used));
                if(dfs(v))
                    peak++;
            }
        }

        if(peak==n){
            cout<<peak<<endl;
            rep(i,1,n+1)
                pos[i]=i;
            rep(i,1,n+1){
                int v=i+colStar;
                if(match[v]<0)
                    continue;
                else{
                    cout<<"R "<<pos[match[v]]<<" "<<i<<endl;

                    rep(x,1,n+1)
                        if(i==pos[x]){
                            pos[x]=pos[match[v]];
                            break;
                        }
                    pos[match[v]]=i;

                }

            }
        }else
            cout<<"-1"<<endl;

        rep(i,0,MAXN)
            adj[i].erase(adj[i].begin(),adj[i].end());

    }

    re 0;
}
bool dfs(int v){
    used[v]=true;
    rep(i,0,adj[v].size()){
        int u=adj[v][i],matched=match[u];
        if(matched<0 || !used[matched] && dfs(matched)){
            match[v]=u;
            match[u]=v;
            return true;
        }
    }
    return false;
}


给几组数据
2
0 1
1 0

1
0

4
0 1 0 1
1 1 0 1
1 0 1 0
0 1 1 0

4
1 1 0 0
1 0 1 0
1 0 0 1
1 0 0 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值