垃圾佬的手套 二分图匹配

题目来源:http://www.fjutacm.com/Problem.jsp?pid=3443

思路:建边时将输入的map[a][b]=0,之后先跑一边最大匹配,在找到匹配点对后,一个个匹配点对枚举,如果这个点对的连接边去掉以后再跑一遍二分图最大匹配不变,则说明这对手套不是肯定的一对;如果最大匹配改变了则说明这点对是必选的,则可以将这一对记录在答案里,最后输出;

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=110;
bool vis[N], mat[N][N];
int n, k;
int dfs(int i, int *pa){
    for(register int j=1; j<=n; ++j){
        if(mat[i][j]&&!vis[j]){
            vis[j]=1;
            if(pa[j]==-1||dfs(pa[j], pa)){
                pa[j]=i;
                return 1;
            }
        }
    }
    return 0;
}
int ans[N]={};
void work(int &Ans, int *pa){
    Ans=0;
    for(register int i=1; i<=n; ++i)
        pa[i]=-1;
    for(register int i=1; i<=n; ++i){
        memset(vis, 0, sizeof(vis));
        Ans+=dfs(i, pa);
    }
}
int main(){
    int pa2[N], pa1[N];
    int x, y, Ans, tmp;
    register int i, j, top=0;
    scanf("%d%d", &n, &k);
    for(i=1; i<=n; ++i)
        for(j=1; j<=n; ++j)
            mat[i][j]=1;
    for(i=1; i<=k; ++i){
        scanf("%d%d",&x,&y);
        mat[x][y]=0;
    }
    work(tmp, pa2);
    for(i=1; i<=n; ++i){
        if(pa2[i]!=-1){
            mat[pa2[i]][i]=0;
            work(Ans, pa1);
            if(Ans!=tmp){
                ans[pa2[i]]=i;
                top++;
            }
            mat[pa2[i]][i]=1;
        }
    }
    if(!top){
        puts("sorry");
        return 0;
    }
    for(i=1; i<=n; ++i){
        if(ans[i]){
            printf("%d %d\n", i, ans[i]);
        }
    }
    return 0;
}

  

 

posted @ 2018-08-14 21:50  Thanks_up  阅读(192)  评论(0编辑  收藏  举报