パイロットペアリング問題|ネットワークストリーム:最大バイナリマッチング(ハンガリーアルゴリズム)

パイロットのペアリングの問題

グレード 10 開始時間 2020年4月21日火曜日10時10分
ディスカウント 0.8 割引時間 2020年5月30日土曜日23:55
遅延提出が可能 番号 閉店時間 2020年5月30日土曜日23:55

問題の説明:第二次世界大戦中、王立空軍は占領国から多数の外国人パイロットを募集しました。王立空軍によって送られる各航空機には、航法スキルと言語で互いに協力できる2人のパイロットが装備されている必要があります。 1人はイギリス人パイロット、もう1人は外国人パイロットです。多くのパイロットの中で、各外国人パイロットは他のいくつかのイギリス人パイロットとうまく協力できます。ペアのパイロットを選択して一度に最も多くの航空機を送る方法。

アルゴリズムの設計:外国人パイロットとイギリス人パイロット間の所定の協力について、イギリス空軍が派遣できるパイロットの最大数を調べます。

データ入力:最初の行には2つの正の整数mとnがあります。nはイギリス空軍のパイロットの総数(n <100)、mは外国人パイロットの数です。外国人パイロットには1〜m、英国人パイロットにはm + 1〜nと番号が付けられています。各行の次の2つの整数iとjは、外国のパイロットiがイギリスのパイロットjと協力できることを示しています。最後に、2 -1で終わります。

結果出力:王立空軍は最も多くのパイロットを送ることができます。

  テスト入力 期待される出力 制限時間 メモリ制限 追加プロセス
テストケース1 テキストとして表示
  1. 510↵
  2. 17↵
  3. 18↵
  4. 26↵
  5. 29↵
  6. 210↵
  7. 37↵
  8. 38↵
  9. 47↵
  10. 48↵
  11. 510↵
  12. -1 -1↵
テキストとして表示
  1. 4↵
1秒 64M 0

        これは2部グラフのマッチング問題であり、最大フローアルゴリズムに変換して解決するか、ハンガリー語アルゴリズムを直接使用できますこの記事では、ハンガリー語のアルゴリズムを直接使用しています。

        アルゴリズムの原理とプロセスを理解するには、ハンガリー語のアルゴリズム(シンプルで理解しやすい)の記事を読んでくださいハンガリー語のアルゴリズムはシンプルで理解しやすく、基本的に貪欲です。ハンガリー語のアルゴリズムのACコードは以下に直接貼り付けられており、わかりやすいコメントは理解しやすいはずです〜

//匈牙利算法解决二部图的最大流问题

#include <cstdio>
#include <cstring>

#define MAXN 105

int m, n;   //二部图左侧有m个,总计有n个
bool connected[MAXN][MAXN];   //图的连接关系
int pre[MAXN] = {0};   //next[j]=i:左侧的 i 点与右侧的 j 点匹配

/* 处理输入与初始化 */
void Init() {
    scanf("%d %d", &m, &n);
    int i, j;
    while (true) {
        scanf("%d %d", &i, &j);
        if (i == -1 && j == -1)
            break;
        connected[i][j] = true;
    }
}

bool vis[MAXN];

/* 寻找左侧的点与右侧匹配 */
bool Find(int left) {
    //依次遍历右部顶点
    for (int right = m + 1; right <= n; right++) {
        //寻找 相邻 且 此次查找没有被考虑过 的右侧点
        if (connected[left][right] && !vis[right]) {
            vis[right] = true;
            //寻找 没有匹配 或 该点的匹配点可以另有匹配 的右侧点
            if(pre[right] == 0 || Find(pre[right])) {
                pre[right] = left;   //匹配
                return true;
            }
        }
    }
    return false;
}

int CalcAns(){
    int ans = 0;
    /* 讨论每一个左部顶点 */
    for(int left = 1; left <= m; left++) {
        memset(vis, false, sizeof(vis));   //每次寻找前需要初始化
        if(Find(left))  //如果能找到
            ans++;  //匹配数字加一
    }
    return ans;
}

int main() {
    Init();
    printf("%d\n", CalcAns());
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

おすすめ

転載: blog.csdn.net/weixin_43787043/article/details/106443018