• P2756 飞行员配对方案问题 网络流 二分图匹配


      

    题目描述

    英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

    对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

    输入输出格式

    输入格式:

    第 1 行有 2 个正整数 m 和 n。n 是皇家空军的飞行员总数(n<100);m 是外籍飞行员数(m<=n)。外籍飞行员编号为 1~m;英国飞行员编号为 m+1~n。

    接下来每行有 2 个正整数 i 和 j,表示外籍飞行员 i 可以和英国飞行员 j 配合。最后以 2个-1 结束。

    输出格式:

    第 1 行是最佳飞行员配对方案一次能派出的最多的飞机数 M。接下来 M 行是最佳飞行员配对方案。每行有 2个正整数 i 和 j,表示在最佳飞行员配对方案中,飞行员 i 和飞行员 j 配对。如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’。

    输入输出样例

    输入样例#1: 复制
    5 10
    1 7
    1 8
    2 6
    2 9
    2 10
    3 7
    3 8
    4 7
    4 8
    5 10
    -1 -1
    输出样例#1: 复制
    4
    1 7
    2 9
    3 8
    5 10 

    注意匈牙利算法vis的运用 !!!vis[]存的是右图的匹配情况

    只用连左图到右图的即可

    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define ll long long
    #define pb push_back
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    #define inf 0x3f3f3f3
    const int N=1000000;
    const int M=1000000;
    int head[M],pos;
    struct Edge
    {
        int nex,to;
    }edge[M];
    void add(int a,int b)
    {
        edge[++pos].nex=head[a];
        head[a]=pos;
        edge[pos].to=b;
    }
    int n,m;
    int vis[N],used[N];
    int flag=0;
    
    bool dfs(int x)
    {
        for(int i=head[x];i;i=edge[i].nex)
        {
            int v=edge[i].to;
    
            if(!used[v])
            {
                used[v]=1;
                if(!vis[v]||dfs(vis[v]))
                {
                    vis[v]=x;return 1;
                }
            }
        }
        return 0;
    }
    
    int find1()
    {
        int ans=0;
        CLR(vis,0);
        rep(i,1,n)
        {
            CLR(used,0);
            if(dfs(i))ans++;
        }
        return ans;
    }
    
    int main()
    {
        RII(n,m);
        int a,b;
        while(RII(a,b))
        {
            if(a==-1&&b==-1)
               break;
            add(b,a);
        }
        int cnt=find1();
    
        if(!cnt)
            printf("No Solution");
        else
        {
            cout<<cnt<<endl;
            rep(i,n+1,m)
            {
                if(vis[i])
                    printf("%d %d
    ",vis[i],i);
            }
        }
        return 0;
    }
    View Code

    网络流

    注意初始化!!!! 

    只要看反向边是否为0即可输出结果

    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define ll long long
    #define pb push_back
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    #define inf 0x3f3f3f3f
    const int N=10000+5;
    const int M=200000+5;
    int head[M],pos;
    struct Edge
    {
        int to,nex=-1,v;
    }edge[M];
    void init()
    {
        pos=-1;
        CLR(head,-1);
    }
    void add(int a,int b,int c)
    {
        edge[++pos].nex=head[a];
        head[a]=pos;
        edge[pos].to=b;
        edge[pos].v=c;
        edge[++pos].nex=head[b];
        head[b]=pos;
        edge[pos].to=a;
        edge[pos].v=0;
    }
    
    int deth[N];
    int bfs(int s,int t)
    {
        CLR(deth,0);
        queue<int>q;
        deth[s]=1;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head[u];i!=-1;i=edge[i].nex)
            {
                int v=edge[i].to;
                if(edge[i].v>0&&deth[v]==0)
                {
                    deth[v]=deth[u]+1;
                    q.push(v);
                }
            }
        }
        return deth[t];
    }
    int dfs(int s,int t,int dis)
    {
        if(s==t)return dis;
        for(int i=head[s];i!=-1;i=edge[i].nex)
        {
            int v=edge[i].to;
            if(deth[v]==deth[s]+1&&edge[i].v!=0)
            {
                int di=dfs(v,t,min(dis,edge[i].v));
                if(di>0)
                {
                    edge[i].v-=di;
                    edge[i^1].v+=di;
                    return di;
                }
            }
        }
        return 0;
    }
    
    int dinic(int s,int t)
    {
        int ans=0;
        while(bfs(s,t))
            while(int di=dfs(s,t,inf))
            ans+=di;
        return ans;
    }
    
    int main()
    {
        int n,m;
        RII(n,m);
        int s=m+1,e=m+2;
        int a,b;
        init();
        while(RII(a,b))
        {
            if(a==-1&&b==-1)break;
            add(a,b,1);
        }
        rep(i,1,n)
        add(s,i,1);
        rep(i,n+1,m)
        add(i,e,1);
        int cnt=dinic(s,e);
        if(cnt==0)
            printf("No Solution!
    ");
        else
        {
            cout<<cnt<<endl;
        }
        for(int i=0;i<=pos;i+=2)
        {
            int a=edge[i].to;int b=edge[i^1].to;
            if(a!=s&&b!=s)
            if(a!=e&&b!=e)
            if(edge[i^1].v!=0)
            {
                printf("%d %d
    ",b,a);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    ElasticSearch(二) Transport Client Connection By Domain
    ElasticSearch(一) Transport Client
    如何把Spring Boot打包成war
    Lucene Query种类
    JAVA Http Basic auth
    Java 多线程系列2——多线程的生命周期及生产消费者模型
    Java 多线程系列1——浅聊JAVA 线程池的一般用法
    JS 实现右下角弹窗
    JS 实现兼容IE图片向左或向右翻转
    Vue Input输入框两侧加减框内数字组件
  • 原文地址:https://www.cnblogs.com/bxd123/p/10829195.html
Copyright © 2020-2023  润新知