zoukankan      html  css  js  c++  java
  • 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

    这个题最直接的就是匈牙利算法,很好用,也很快。

    #include<stdio.h>
    #include<string.h>
    const int MAXN=101;
    bool mapp[MAXN][MAXN];
    bool vis[MAXN];
    int pre[MAXN];
    int m,n;
    bool find(int x)
    {
          for(int i=1;i<=n;i++)
          {
                if(mapp[x][i]==true&&vis[i]==false)
                {
                      vis[i]=true;
                      if(pre[i]==0||find(pre[i]))
                      {
                            pre[i]=x;
                            pre[x]=i;//此处将通过的边信息存储下来。
                            return true;
                      }
                }
          }
          return false;
    }
    int main()
    {
    
          scanf("%d%d",&m,&n );
          int a,b;
          memset(mapp,false , sizeof(mapp));
          while(scanf("%d%d",&a,&b)&&a!=-1&&b!=-1)
          {
                mapp[a][b]=true;
          }
          int ans=0;
          memset(pre,0 , sizeof(pre));
          for(int i=1;i<=m;i++)
          {
                memset(vis,false , sizeof(vis));
                if(find(i)) ans++;
          }
          if(ans==0)
                puts("No Solution!");
          else
          {
                printf("%d
    ",ans );
                for(int i=1;i<=m;i++)
                {
                      if(pre[i])
                      printf("%d %d
    ",i,pre[i] );
                }
          }
    
          return 0;
    }

    当然也可以网络流,飞行员和飞行员连接,容量是一,再创建源点和汇点与飞行员连接,容量还是1,这是保证每个外籍飞行员只能与一个英国飞行员连接。我用的是Ek算法。

    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int MAXN=205;
    const int INF=0x3f3f3f3f;
    int n,m;
    int mapp[MAXN][MAXN];
    bool vis[MAXN];
    int pre[MAXN];
    int ma[MAXN];
    bool bfs(int s,int e)
    {
        int p;
        memset(pre,-1 , sizeof(pre));
        memset(vis,false , sizeof(vis));
        queue<int>q;
        q.push(s);
        while(!q.empty())
        {
            p=q.front();
            q.pop();
            for(int i=0;i<=m+n+1;i++)
            {
                if(!vis[i]&&mapp[p][i]>0)
                {
                    vis[i]=true;
                    pre[i]=p;
                    if(i==e)
                        return true;
                    q.push(i);
                }
            }
        }
        return false;
    
    }
    int EK(int s,int e)
    {
        int flow=0,d;
        while(bfs(s,e))
        {
            d=INF;
            for(int i=e;i!=s;i=pre[i])
            {
    
                if(i!=e&&pre[i]!=s&&i!=s&&pre[i]!=e)
                {
                    ma[pre[i]]=i;//此处存下连接信息
                }
                d=min(d,mapp[pre[i]][i]);
            }
            for (int i =e; i !=s ;i=pre[i])
            {
                mapp[pre[i]][i]-=d;
                mapp[i][pre[i]]+=d;
            }
            flow+=d;
        }
        return flow;
    }
    int main()
    {
    
        scanf("%d%d",&m,&n);
        int x,y;
        memset(mapp,0,sizeof(mapp));
        memset(ma, false, sizeof(ma));
        while(scanf("%d%d",&x,&y)&&x!=-1&&y!=-1)
        {
            mapp[x][y+m]+=1;
        }
        int e=m+n+1;
        for(int i=1;i<=m;i++)
        mapp[0][i]+=1;
        for(int i=m+1;i<e;i++)
        mapp[i][e]+=1;
        int ans=EK(0,e);
        if(ans==0)
        {
            printf("No Solution!
    ");
        } 
        else
        {
            printf("%d
    ",ans );
            for(int i=1;i<=m;i++)
            {
                if(ma[i])
                    printf("%d %d
    ",i,ma[i]-m);
            }
        }
        return 0;
    }
  • 相关阅读:
    Java线程:线程的交互
    Java线程:线程的同步与锁
    重载,继承,重写和多态的区别
    Java线程:线程状态的转换
    Java线程:线程栈模型与线程的变量
    Java线程:创建与启动
    Java线程:概念与原理
    Android上dip、dp、px、sp等单位说明
    Java学习之路:不走弯路,就是捷径
    谷歌大牛 Rob Pike 的 5 个编程原则
  • 原文地址:https://www.cnblogs.com/-xiangyang/p/9220241.html
Copyright © 2011-2022 走看看