EK算法应用,构图(POJ1149)

题目链接:http://poj.org/problem?id=1149

题意中有一点要注意,否则构图就会有问题,每个顾客走后,被打开过的那些猪圈中的猪都可以被任意的调换到其他开着的猪圈中。

这里的构图不是单一的相邻,以及容量了,区别在于:他还要求这个容量,和连线。

这里的构图是,以顾客为节点,源点s,汇点t,源点到顾客的容量是:顾客所能得到的猪的和cap[s][i] += h[tmp];

但是,要是这里有一点要注意的是,顾客与顾客之间的容量,为无穷大,因为上一个顾客有多少,就能够给相邻顾客多少,这里,什么是相邻的顾客?

就是说,有公共钥匙的人啦!

老实说,这个构图,我一开始没有想到,也是借鉴了别人的哦,再加上了自己的理解。

#include <stdio.h>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;


const int INF = 0x1f1f1f1f;
const int MAXN = 110;

int cap[MAXN][MAXN];


int EK(int s, int t) {
    queue<int> q;
    int flow[MAXN][MAXN];
    int pre[MAXN];
    int node[MAXN];
    int maxflow=0;

    int u,v;

    memset(flow, 0, sizeof(flow));
    while(true) {
        memset(node, 0, sizeof(node));
        node[s] = INF;
        q.push(s);
        while(!q.empty()) {
            u = q.front();
            q.pop();
            for(v = 0; v <= t; ++v)
                if(!node[v] && cap[u][v] > flow[u][v]) {
                    q.push(v);
                    node[v] = min(node[u],cap[u][v]-flow[u][v]);
                    pre[v] = u;
                }
        }
        if(node[t] == 0) break;
        for(int u = t; u != s; u = pre[u]) {
            flow[pre[u]][u] += node[t];
            flow[u][pre[u]] -= node[t];
        }
        maxflow += node[t];
    }
    return maxflow;
}


int main() {
    int i, j;
    int nn, mm;
    int tmp, m;
    int s, t;
    int h[1010];        ///猪的头数
    int last[1010];     ///记录猪圈上一个拥有钥匙的人

    while(scanf("%d %d", &mm, &nn) != EOF) {
        memset(cap,0,sizeof(cap));
        memset(last,0,sizeof(last));

        s = 0, t = nn+1;

        for(i = 1; i <= mm; ++i)
            scanf("%d", &h[i]);     

        for(i = 1; i <= nn; ++i) {      ///客户数
            scanf("%d", &m);            ///有几片钥匙
            for(j = 0; j < m; ++j) {
                scanf("%d", &tmp);
                if(last[tmp] == 0)
                    cap[s][i] += h[tmp];
                else
                    cap[last[tmp]][i] = INF;    ///客户到客户
                last[tmp] = i;
            }
            scanf("%d", &cap[i][t]);        ///客户到汇点
        }
        
        printf("%d
",EK(s, t));
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/TreeDream/p/5510100.html