BZOJ 1280: Emmy卖猪pigs 网络最大流,神奇建图

来源:互联网 发布:mac官网口红价格 编辑:程序博客网 时间:2024/05/22 08:20

Description
Emmy在一个养猪场工作。这个养猪场有M个锁着的猪圈,但Emmy并没有钥匙。顾客会到养猪场来买猪,一个接着一个。每一位顾客都会有一些猪圈的钥匙,他们会将这些猪圈打开并买走固定数目的猪。 所有顾客有的钥匙和他们需要买猪的数量在事先都告诉了Emmy,于是Emmy要订一个计划,使得卖出去的猪最多。 买卖的过程是这样的:一个顾客前来,并打开所有他可以打开的猪圈。然后Emmy从这些猪圈里牵出固定数目的猪卖给顾客(最多只能和顾客需要数相等),并可以重新安排这些开着的猪圈中的猪。 每个猪圈可以存放任意数目的猪。 写一个程序,使得Emmy能够卖出去尽可能多的猪。
Input
第一行有两个整数:M和N,表示猪圈数和顾客数。 第二行有M个整数,表示每个猪圈初始时有多少猪。 接下来的N行按照前来的次序描述了每一个顾客,每行的格式如下: A K1 K2…KA B A表示该顾客拥有的钥匙数,K1…KA表示每个钥匙所对应的猪圈,B表示该顾客需要购买的猪的数目。
Output
仅包含一个整数,即最多能卖出去的猪的数目。
Sample Input
3 3

3 1 10

2 1 2 2

2 1 3 3

1 2 6

Sample Output
7
HINT

1 ≤ M ≤ 1000
1 ≤ N ≤ 100

网络流建模汇总上的第一个例题。
http://wenku.baidu.com/link?url=5vBWTkDBeEKYqNiwsqWFdhL7cU-KNXgzYPKriPifFCXw8Qs8DWBrlScSSiNkFMUSGsTkuPKlePeqhlFVk62z0QoCnTKqis9oUs93FXyVjdW

直接说最后的建图过程好了,这是集训队火山爷教我的
这里写图片描述

建一个超级源点0..超级汇点n+1

以客户作为节点..

超级源点根据第一个拥有猪圈的客户和超级源点连线..容量就是第一个客户累计可以得到多少头猪..

因为第一个打开猪圈的客户可以取得所有的猪..所以超级源点和客户之间的连线容量就表示第一个打开猪圈的

人虽能够得到的数量..

然后接下来的每一个人与前一个打开猪圈的人之间连线..容量为INF..因为可以从别的猪圈调猪过来..

然后求得的最大流就是可以卖得的猪的数量..

至于为什么这么建图是正确的,证明论文里有。

//BZOJ 1280 PIGS#include <bits/stdc++.h>using namespace std;const int maxn = 510;const int maxm = 100010;const int inf = 0x3f3f3f3f;struct G{    int v, cap, next;    G() {}    G(int v, int cap, int next) : v(v), cap(cap), next(next) {}} E[maxm];int p[maxn], T;int d[maxn], temp_p[maxn], qw[maxn]; //d顶点到源点的距离标号,temp_p当前狐优化,qw队列void init(){    memset(p, -1, sizeof(p));    T = 0;}void add(int u, int v, int cap){    E[T] = G(v, cap, p[u]);    p[u] = T++;    E[T] = G(u, 0, p[v]);    p[v] = T++;}bool bfs(int st, int en, int n){    int i, u, v, head, tail;    for(i = 0; i <= n; i++) d[i] = -1;    head = tail = 0;    d[st] = 0;    qw[tail] = st;    while(head <= tail)    {        u = qw[head++];        for(i = p[u]; i + 1; i = E[i].next)        {            v = E[i].v;            if(d[v] == -1 && E[i].cap > 0)            {                d[v] = d[u] + 1;                qw[++tail] = v;            }        }    }    return (d[en] != -1);}int dfs(int u, int en, int f){    if(u == en || f == 0) return f;    int flow = 0, temp;    for(; temp_p[u] + 1; temp_p[u] = E[temp_p[u]].next)    {        G& e = E[temp_p[u]];        if(d[u] + 1 == d[e.v])        {            temp = dfs(e.v, en, min(f, e.cap));            if(temp > 0)            {                e.cap -= temp;                E[temp_p[u] ^ 1].cap += temp;                flow += temp;                f -= temp;                if(f == 0)  break;            }        }    }    return flow;}int dinic(int st, int en, int n){    int i, ans = 0;    while(bfs(st, en, n))    {        for(i = 0; i <= n; i++) temp_p[i] = p[i];        ans += dfs(st, en, inf);    }    return ans;}int pig[maxn], st, en;int L[maxn];vector <int> a[maxn]; //每个顾客开的猪圈int m, n;int main(){    scanf("%d%d", &m,&n);    st = 0, en = n+1;    init();    for(int i=1; i<=m; i++) scanf("%d",&pig[i]);    for(int i=1; i<=n; i++){        int x, y;        scanf("%d", &x);        while(x--){            scanf("%d",&y);            a[i].push_back(y);        }        scanf("%d",&y);        add(i,en,y);    }    for(int i=1; i<=n; i++){        for(int j=0; j<a[i].size(); j++){            int v=a[i][j];            if(!L[v]){                L[v]=i;                add(st,i,pig[v]);            }            else{                add(L[v],i,inf);                L[v]=i;            }        }    }    int ans=dinic(st,en,en+1);    printf("%d\n", ans);    return 0;}
0 0
原创粉丝点击