代码改变世界

POJ1149最大流

2013-07-30 22:12  凝月流风  阅读(230)  评论(0编辑  收藏  举报

 

难度在于建图,剩下的就是求最大流问题了。

贴上我的实现代码

//题目的难度在于如何建图,将每一个客户当做点,另外添加一个源点s和汇点t,每个客户点建一条有向边指向汇点t,容量为该客户要购买的猪的数量;
//若客户i是猪圈j的第一个访问者,则从源点s建一条边指向节点i,容量为猪圈的初始猪数,若客户i不是猪圈j的第一个客户,而该猪圈的上一个客户(pre数组记录)是
//x,那么从x建一条边指向i, 容量为正无穷,支持建图完成,剩下只需算出s到t的最大流即可,以下用EK算法实现; 
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
const int MAXN = 1001;
const int N = 101;
const int MAX = 0x7FFFFFFF;
int c[N][N], path[N], pre[MAXN], flow[N]; //pre数组记录某猪圈的前一个访问者,建图需要 
queue<int>Q;
int Edmonds_Karp(int s, int t) {
  int sum = 0;
  int u, v;
  while (1) {
      memset(path, -1, sizeof(path));
      while (!Q.empty())
        Q.pop();
    flow[s] = MAX;
    Q.push(s);
    while (!Q.empty() && path[t] == -1) {
         u = Q.front(); Q.pop();
         for (v = 0; v <= t; v++) {
           if (c[u][v] && path[v] == -1) {
             path[v] = u;
             flow[v] = flow[u] < c[u][v] ? flow[u] : c[u][v];
             Q.push(v);
           } 
         }
    }
    if (path[t] != -1) {
      sum += flow[t];
      v = t;
      while (v != s) {
          c[path[v]][v] -= flow[t];
          c[v][path[v]] += flow[t];
          v = path[v];
      }
    } else {
      break;
    }
  }
  return sum;
}

int main()
{
  int n1, k, order, i, j, n, m;
  int val[MAXN];
  while (scanf("%d%d", &m, &n) != EOF) {
      memset(c, 0, sizeof(c));
      memset(pre, 0, sizeof(pre));
      //以下为读取数据并建图
    for (i = 1; i <= m; i++)
        scanf("%d", &val[i]);
      for (i = 1; i <= n; i++) {
        scanf("%d", &n1);
        for (j = 0; j < n1; j++) {
            scanf("%d", &order);
            if (!pre[order]) {
                c[0][i] += val[order]; 
            }else {
                c[pre[order]][i] = MAX;
            }
            pre[order] = i;
        }
        scanf("%d", &k);
        c[i][n+1] = k; 
      }
      //求最大流 
      int sum = Edmonds_Karp(0, n+1);
      printf ("%d\n", sum);
  }
  return 0;
}