POJ 1274 The Perfect Stall [图论.二分图.匈牙利算法] 《挑战程序设计竞赛》3.5

题目大意

农夫有N头牛,M个坑位,每头牛都只在特定的几个坑位内才能产奶。寻求最大产奶方案。

输入格式

第一行N,M两个数字
接下来N行,每行第一个数字表示该行接下来有几个数字。表示第i头牛在哪些坑位里能产奶

输出格式

输出最大匹配数

样例输入

5 5
2 2 5
3 2 3 4
2 1 5
3 1 2 5
1 2 

样例输出

4

题解

二分图模板题。可以用匈牙利算法或者最大流来求解。这里用匈牙利算法来求解。
关于匈牙利算法,送上两篇优秀博客。第一篇生动形象,非常容易理解,第二篇比较严谨。建议按顺序阅读。

简单易懂: https://blog.csdn.net/dark_scope/article/details/8880547
严谨详细:http://www.renfei.org/blog/bipartite-matching.html

这两篇博客里的代码还是有所不同的,第一篇的代码更容易理解,更简单,把二分图分成两个独立的部分,在dfs搜索的时候每次都是从二分图的同一个部分向另一部分搜索。第二篇中的代码不区分二分图为两个独立的部分,只是按编号来区分不同的节点,在同一个图中搜索,所以matching的时候要多判断一次,并且引入了更多的概念。实际上原理和最大流都是相通的啊,都是在增广。

代码

#include 
#include 
#include 
#define MAXN 510
#define MAXM 510
using namespace std;
int N, M;
vector<int> G[MAXN];
int stall[MAXM];
bool used[MAXM];

bool dfs(int s) {
  int len = G[s].size();
  for (int i = 0; i < len; i++) {
    int v = G[s][i];
    if (!used[v]) {
      used[v] = true;
      if (stall[v] == -1 || dfs(stall[v])) {
        stall[v] = s;
        return true;
      }
    }
  }
  return false;
}

int hungarian() {
  int ans = 0;
  memset(stall, -1, sizeof(stall));
  for (int i = 1; i <= N; i++) {
    memset(used, false, sizeof(used));
    if (dfs(i)) {
      ans++;
    }
  }
  return ans;
}

int main() {
  while (cin >> N >> M) {
    for (int i = 1; i <= N; i++) {
      G[i].clear();
      int cnt;
      cin >> cnt;
      for (int j = 0; j < cnt; j++) {
        int the_stall;
        cin >> the_stall;
        G[i].push_back(the_stall);
      }
    }

    cout << hungarian() << endl;
  }
  return 0;
}

你可能感兴趣的:(挑战程序设计竞赛,POJ,图论)