HDU - 2819 Swap——【二分图最大匹配】

Swap

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4467    Accepted Submission(s): 1664
Special Judge


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
 

Source
 这道题的提议大致就是给你个矩阵,问你能不能移动这个矩阵的行或列使得矩阵的主对角线元素都为1,如果可以输出m移动次数,以及移动的是哪几行或那几列。

这道题当时卡了很久,然后在网上搜的题解,然后又自己理解理解,用了一天时间才把这道题搞明白。如果能使主对角线的元素全为1,说明更新完原有x和y的匹配关系过后新生成的匹配个数恰好为n。意思就是求这组数据的最大匹配并且最大匹配为N,才能符合题意。其余部分我将结合代码一起讲解。

#include<bits/stdc++.h>
using namespace std;

int e[101][101];
int match[1001],vis[1001];
int a[1001],b[1001];//a,b用来记录交换的行数/列数
int n;

bool dfs(int u){
    int i;
    for(i=1;i<=n;i++){
        if(!vis[i]&&e[u][i]){
            vis[i]=1;//标记该点已经访问过
            if(!match[i]||dfs(match[i])){
                match[i]=u;//更新配对关系
                return 1;
            }
        }
    }
    return 0;
}

int main(){
    while(~scanf("%d",&n)){
        memset(e,0,sizeof(e));
        memset(match,0,sizeof(match));//用来记录匹配关系
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                scanf("%d",&e[i][j]);
            }
        }
        int ans=0,k=0;
        //要是重构完匹配关系后使主对角线的元素都为1则最大匹配为n
        for(int i=1;i<=n;i++){
            memset(vis,0,sizeof(vis));
            if(dfs(i)) ans++;
        }
        /*printf("最大匹配关系\n");
        for(int i=1;i<=n;i++){
            printf("%d  %d\n",i,match[i]);可以自己先输出一下更新后的匹配关系在去找要移动的行或者列
        }*/
        if(ans<n){
            printf("-1\n");
        }
        else{

            for(int i=1;i<=n;i++){
                //查找最大匹配关系,然后移动对应的行/列
                if(match[i]){
                    while(match[i]!=i){
                        a[k]=i;//储存其对应的行数
                        b[k]=match[i];//记录要交换的列
                        swap(match[a[k]],match[b[k]]);//交换列数
                        k++;
                        /*因为主对角线的元素全为1所以x==y,假设x1,y4
                        是更新完匹配关系后的匹配,但要是x==y,因为y4==x4,
                        所以就去找x4对应的列数和x1对应的列数y4交换上的x4==y4*/
                    }
                }
            }
            printf("%d\n",k);
            for(int i=0;i<k;i++){
                printf("C %d %d\n",a[i],b[i]);
            }
        }
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/xiang_hehe/article/details/80670337