现在的位置: 首页 > 综合 > 正文

POJ-1149 PIGS 网络流

2012年03月04日 ⁄ 综合 ⁄ 共 2017字 ⁄ 字号 评论关闭

题意:一个农夫要把养殖的猪卖出去,现有M个猪圈,农夫自己没有猪圈的钥匙。现有N个客户要来买猪,每个客户手中有Ai把钥匙,分别表示成猪圈的编号,并且每个客户需要买一定的猪。这些客户依次过来(编号从小到大),现在农夫可以选择如何将这些猪卖给每一个客户,只要头数不超过需求即可。农夫在处理好每一笔交易后能够将打开的猪圈门之内的猪任意分配。现在问农夫能够卖出最多的猪的数量。

解法:通过这一题,发现构边的时候其实是有很多技巧的,这题如果把猪圈放到图中的话那么将成为一道不可做题。原因是时间复杂度和空间复杂度太高了。其实可以画出一个简图,然后再通过合并边和合并点来简化构图。由于农夫能够在打开猪圈后任意分配猪。因此如果第j个客户能够买第i个客户买过的猪圈中的猪,那么就可以视作第j个客户代替i先买。也就是说这里有一个边的合并过程。如果每个人都有这种代理的想法,那么农夫(相当于源点)就只要提供猪给第一个打开某个猪圈的客户。因此最后的构边过程可以描述如下:

1.第i个客户如果无法找到有代理人的猪圈,那么自己成为当前猪圈的代理人,从源点连一条边到i,容量为猪圈中猪的总数;

2.如果该号猪圈有代理人,那么这个猪圈的代理人 j(注意并不止一个)连一条边到客户 i,容量无穷大,i 也成为该猪圈的代理人。注意这里有一个优化就是只要从最近的代理人那里连一条边到 i 即可,因为其他代理人的边可以通过最近的代理人传递过来。

3.每个客户连一条到汇点,容量为买猪的数量。

代码如下:

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;

int M, N;
const int SS = 0, TT = 103;
const int INF = 0x3f3f3f3f;
// M个猪圈和N个顾客 

struct Edge {
    int v, c, next;
}e[20005];


int cap[1005], link[1005];
int idx, head[105];
int que[105];
int level[105]; // 对每个顶点分一个层
int front, tail;

void insert(int a, int b, int c) {
    e[idx].v = b, e[idx].c = c;
    e[idx].next = head[a];
    head[a] = idx++;
}

bool bfs() {
    front = tail = 0;
    que[tail++] = SS;
    memset(level, 0xff, sizeof (level));
    level[SS] = 0;
    while (front != tail) {
        int u = que[front++];
        for (int i = head[u]; i != -1; i = e[i].next) {
            if (!(~level[e[i].v]) && e[i].c) {
                level[e[i].v] = level[u] + 1;
                if (e[i].v == TT) return true;
                que[tail++] = e[i].v;
            }
        }
    }
    return ~level[TT];
}

int dfs(int u, int sup) {
    if (u == TT) return sup;
    int tf = 0, f;
    for (int i = head[u]; i != -1; i = e[i].next) {
        if (level[u]+1 == level[e[i].v] && e[i].c && (f = dfs(e[i].v, min(e[i].c, sup-tf)))) {
            tf += f;
            e[i].c -= f, e[i^1].c += f;
            if (tf == sup) return sup;
        }
    }
    if (!tf) level[u] = -1;
    return tf;
}

int dinic() {
    int ret = 0;
    while (bfs()) {
        ret += dfs(SS, INF);
    }
    return ret;
}

int main() {
    while (scanf("%d %d", &M, &N) != EOF) {
        int x, y, tot;
        idx = 0;
        memset(head, 0xff, sizeof (head));
        for (int i = 1; i <= M; ++i) {
            link[i] = -1;
            scanf("%d", &cap[i]);
        }
        for (int i = 1; i <= N; ++i) {
            tot = 0;
            scanf("%d", &x);
            for (int j = 1; j <= x; ++j) {
                scanf("%d", &y);
                if (~link[y]) { // 如果这个节点已经在其他客户出现
                    insert(link[y], i, INF);
                    insert(i, link[y], 0);
                } else {
                    tot += cap[y];
                }
                link[y] = i;
            }
            if (tot) {
                insert(SS, i, tot);
                insert(i, SS, 0);
            }
            scanf("%d", &y);
            insert(i, TT, y);
            insert(TT, i, 0);
        }
        printf("%d\n", dinic());
    }
    return 0;
} 

 

 

抱歉!评论已关闭.