HDU-2819 Swap(二分图最大匹配,路径记录)

 

题意:给你一个0,1的矩阵然后你现在可以多次交换任意的两行或者两列
使得该矩阵的对角线全为1.如果不能则输出-1
思路:我们可以把行列交换看做一种匹配,要是得对角线的所有为1
就要把所有的1交换到G[i][i]的位置,比如某个1在(0,1){初始行号为0}
那么我们就可以把它交换到(0,0)或者(1,1),即交换到行号相同或者列号相同的位置
同时题中要求的交换是得到的最终位置,而不是交换过程中的位置
所以对于每一个行i都要进行匹配一次,就转换成了最大匹配问题
当然记录路径我们可以是换行也可以是换列

 

完整代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int G[105][105];
int n;
struct Path
{
    int x,y;
}path[1000];
int match[105];
int vis[105];
int cnt,ans;
bool Find(int u){
    for(int i = 1;i<=n;i++){
        if(!vis[i]&&G[u][i]){
            vis[i] = 1;
            if(!match[i]||Find(match[i])){
                match[i] = u;//这里的match是列对行的匹配 
                return true;
            }
        }
    }
    return false;
}
void printPath(){
    int tmp;
    for(int i = 1;i<=n;i++){
        if(match[i]!=i){
            for(int j =i;j<=n;j++){
                if(match[j]==i){
                    path[cnt].x = i;
                    path[cnt++].y = j;
                    tmp = match[i];
                    match[i] = match[j];
                    match[j] = tmp;//表示列被交换
                }
            }
        }
    }
}
int Count(){
    int count = 0;
    memset(match,0,sizeof(match));
    for(int i =0;i<=n;i++){
        memset(vis,0,sizeof(vis));
        if(Find(i)) count++;
    }
    return count;
}
int main(){
    while(cin>>n){
        for(int i = 1;i <= n; i++){
            for(int j = 1; j <= n; j++){
                cin>>G[i][j];
            }
        }
        ans = cnt = 0;
        if(Count()!=n) cout<<-1<<endl;
        else{
            printPath();
            cout<<cnt<<endl;
            for(int i=0;i<cnt;i++){
                printf("C %d %d\n",path[i].x,path[i].y);
            }            
        }
    }
    return 0;
}

 

posted @ 2019-08-12 10:21  Tianwell  阅读(144)  评论(0编辑  收藏  举报