zoukankan      html  css  js  c++  java
  • P2756 飞行员配对方案问题

    传送门

    二分图

    稍微讲一下二分图:

    就是一个图分成两个部分A和B,这个图的无向边只连接不同的两个部分,即边不能在A或B的内部自己连自己

    然后问你最大能找到多少匹配

    匹配是指 A中的一个点与B中的一个点有边 并且 这两个点都还没有与其它点匹配

    这种问题一般用匈牙利算法:

      匈牙利算法的思想很简单

      对于一个点a能否找到另一个点匹配

      深搜a

      如果与a相连的这个点b还没匹配

      那么毫无问题a可以和b匹配

      但是如果b有匹配了

      没事,去问一下与b匹配的点能不能找其它的点匹配

      方法就是继续深搜(深搜与b匹配的点能否找到再另一个点匹配......)

      然后一直下去

      如果最终找到了

      回来,更新匹配


    本题是十分显然的二分图

    把每个英国飞行员连一条边到外籍飞行员上

    用匈牙利算法找到最大匹配

    顺便输出存储匹配的数组match就OK

    当然也可以用网络流,然而不如二分图好写

    (能用匈牙利为什么要用网络流..)

    顺便提一下网络流怎么写:

    建两个虚拟节点0和n+1,用0节点连接所有的外籍飞行员,用n+1连接所有英国飞行员

    然后所有的边边权都为1

    最后从0到n+1跑最大流就可以了

    以下为匈牙利算法(网络流是不可能有的)

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    inline int read()
    {
        register int x=0; int f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }//快读
    int fir[10007],to[10007],from[10007],cnt;
    inline void add(int &a,int &b)
    {
        from[++cnt]=fir[a];
        fir[a]=cnt;
        to[cnt]=b;
    }//链式前向星存图
    int match[107];
    //匹配数组(划重点),match[i]表示与 编号为i的英国飞行员 的匹配的外籍飞行员的编号
    int n,m,ans;
    bool vis[107];
    inline bool dfs(int x)//如果dfs返回1就表示找到了一种方案(即编号为x的外籍飞行员找到了一个英国飞行员可以匹配)
    {
        for(int i=fir[x];i;i=from[i])
        {
            int u=to[i];
            if(vis[match[u]]) continue;
            vis[match[u]]=1;
            if(!match[u]||dfs(match[u]))//如果这个英国飞行员u还没被匹配,或者与Ta匹配的外籍飞行员可以找另一个人匹配
            {
                match[u]=x;//那么就把这个英国飞行员u的匹配的人改变成x号的外籍飞行员
                return 1;//并返回
            }
        }
    return 0;
    }//匈牙利算法
    int main()
    {
        int a,b;
        cin>>n>>m;
        while(1)
        {
            a=read(); b=read();
            if(a==-1&&b==-1) break;
            add(a,b);//存图
        }
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            if(dfs(i))
              ans++;//多找到一种方案就把最大匹配数加1
        }
        cout<<ans<<endl;
        for(int i=1;i<=m;i++)
            if(match[i])//如果这个英国飞行员有人可以匹配
                printf("%d %d
    ",match[i],i); //输出每个外籍飞行员的编号和与之匹配的英国飞行员的编号
        return 0;
    }
  • 相关阅读:
    boost库:函数对象
    boost库:智能指针
    linux 查看和修改文件时间
    linux正则表达式
    UVA
    UVA
    UVA
    UVA
    UVA
    对JavaScript的认识?
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9508310.html
Copyright © 2011-2022 走看看