zoukankan      html  css  js  c++  java
  • 垃圾佬的手套

    Problem Description

    垃圾佬有n副手套。

    不幸的是,垃圾佬把它们都弄乱了。幸运的是,垃圾佬现在有一些关于手套的信息,他希望从中尽可能多地推测出正确的手套配对信息。

    假设n只左手的手套,编号为1,2,3...,n,且n只右手的手套也依次为1,2,3,...,n。

    从垃圾佬现在的信息中,可以知道,第i只左手手套肯定不是跟第j只右手手套配对。

    请帮助垃圾佬尽可能多地推测出正确的手套配对方案。

    Input

    输入第一行有两个整数n,m,表示垃圾佬有n副手套以及m对信息。

    接来下的m行中,每行有两个数a和b,表示左手手套a肯定不是跟右手手套b配对。

    数据保证合法。即不会出现有一只手套跟所有的手套都不配对的情况。

    1<=n<=100

    0<=m<=n*(n-1)/2

    Output

    输出有若干行。

    每行两个整数a,b,表示左手手套a一定是跟右手手套b配对的。

    请按左手手套的编号a从小到大输出。

    若不能推测出任意一条正确的配对信息,则输出一行"sorry",不包含引号。

    SampleInput
    3 3
    1 3
    2 1
    1 2
    SampleOutput
    1 1


    题意:题意也有点不明了,他的意思其实是说,本来所有的手套都可以互相配对的,然后他给出m组不能配对的关系,
    然后问你在保证最大配对的情况下,哪些是必须要这样配对的


    思路:既然说了要求最大配对,那我们就可以想到二分图,然后问题是哪些是必须要这样配对的,
    我们先求出最大匹配,然后就可以枚举每一条配对的边,看一下删掉之后再求最大

    匹配时是多少,如果最大匹配依然相同,说明当前这条边可有可无,如果最大匹配不同了,
    说明当前这条边已经影响到了最大匹配,是必要的,我们就记录下来


    这里我们用到了有点类似于求割点的方法,枚举求哪些是必要的

    #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
    ", i, ans[i]);
            }
        }
        return 0;
    }
  • 相关阅读:
    Electron应用打包、自动升级
    使用javascript处理nginx的请求
    使用Electron开发桌面应用
    VSCode、VBox搭建C/C++开发环境
    树莓派搭建Nexus2私服
    Tom猫小游戏功能实现
    如何配置webpack让浏览器自动补全前缀
    git 常用操作
    数组的一些常用操作
    ES6 的模块化
  • 原文地址:https://www.cnblogs.com/Lis-/p/9522100.html
Copyright © 2011-2022 走看看