POJ 1149 PIGS 最大流

有N个顾客,M个猪圈分别有 Ai 头,顾客依次打开一些猪圈 Oi ,购买一定数量 Ci 猪,开着的猪圈里的猪可以相互调动,下一个顾客来之前重新关上,问最终最多能卖出多少头猪。

有很明显的流动关系。
如果分阶段考虑猪圈,那么打开的猪圈间的调动关系即相互流动,每轮结束后,需要出售给顾客,即流向顾客。
那么构图显然,原点连向第一阶段各猪圈,容量为猪的初始头数,各阶段同猪圈间依次连边,打开的猪圈连向下阶段,以及当前阶段的顾客。顾客连向汇点,容量为最多购买头数。

另一种角度,由于猪圈的数量是不断变化的,因此可以分阶段考虑,最优方案下各阶段猪圈的数目是常量,令 xi,j 表示第 i 阶段第j个猪圈的数目。
由常量性质得,对每一个 xi,j=xi1,k(j,kOi)=xi+1,p+ci
由范围限制得: x1,j=Aj;ciCi
即流量平衡与流量限制。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ms(i) memset(i,0,sizeof i)
using namespace std;
const int inf = 0x3f3f3f3f, N = 10005, M = 600005;

int level[N], cnt, v[M], w[M], p[M], h[N], q[M], s, t;
void add(int a, int b, int c) {
    p[++cnt] = h[a]; v[cnt] = b; w[cnt] = c; h[a] = cnt;
    p[++cnt] = h[b]; v[cnt] = a; w[cnt] = 0; h[b] = cnt;
}

bool bfs() {
    int f = 0, r = 0, u, i;
    memset(level, -1, sizeof level);
    q[r++] = s; level[s] = 1;
    while (f < r) {
        u = q[f++];
        for (i = h[u]; i; i = p[i]) {
            if (w[i] && level[v[i]] == -1) {
                level[v[i]] = level[u] + 1;
                q[r++] = v[i]; if (v[i] == t) return 1;
            }
        }
    }
    return false;
}

int dfs(int u, int low) {
    int i, tmp = 0, res = 0;
    if (u == t) return low;
    for (i = h[u]; i && res < low; i = p[i]) {
        if (w[i] && level[v[i]] == level[u] + 1) {
            tmp = dfs(v[i], min(w[i], low - res));
            w[i] -= tmp; w[i ^ 1] += tmp; res += tmp;
        }
    }
    if (!res) level[u] = -1;
    return res;
}

int dinic() {
    int ans = 0;
    while (bfs()) ans += dfs(s, inf);
    return ans;
}
int a[N], pre[N];
int main() {
    int i, j, k, n, m;
    while (scanf("%d%d", &n, &m) == 2) {
        s = 0; t = n + 1; cnt = 1;
        ms(pre); ms(h);
        for (i = 1; i <= n; ++i) scanf("%d", &a[i]);
        for (i = 1; i <= m; ++i) {
            scanf("%d", &k);
            while (k--) {
                scanf("%d", &j);
                if (!pre[j]) add(s, i, a[j]);
                else add(pre[j], i, inf);
                pre[j] = i;
            }
            scanf("%d", &k);
            add(i, t, k);
        }
        printf("%d\n", dinic());
    }
    return 0;
}

PIGS

Description

Mirko works on a pig farm that consists of M locked pig-houses and Mirko can’t unlock any pighouse because he doesn’t have the keys. Customers come to the farm one after another. Each of them has keys to some pig-houses and wants to buy a certain number of pigs.
All data concerning customers planning to visit the farm on that particular day are available to Mirko early in the morning so that he can make a sales-plan in order to maximize the number of pigs sold.
More precisely, the procedure is as following: the customer arrives, opens all pig-houses to which he has the key, Mirko sells a certain number of pigs from all the unlocked pig-houses to him, and, if Mirko wants, he can redistribute the remaining pigs across the unlocked pig-houses.
An unlimited number of pigs can be placed in every pig-house.
Write a program that will find the maximum number of pigs that he can sell on that day.

Input

The first line of input contains two integers M and N, 1 <= M <= 1000, 1 <= N <= 100, number of pighouses and number of customers. Pig houses are numbered from 1 to M and customers are numbered from 1 to N.
The next line contains M integeres, for each pig-house initial number of pigs. The number of pigs in each pig-house is greater or equal to 0 and less or equal to 1000.
The next N lines contains records about the customers in the following form ( record about the i-th customer is written in the (i+2)-th line):
A K1 K2 … KA B It means that this customer has key to the pig-houses marked with the numbers K1, K2, …, KA (sorted nondecreasingly ) and that he wants to buy B pigs. Numbers A and B can be equal to 0.

Output

The first and only line of the output should contain the number of sold pigs.

Sample Input

3 3
3 1 10
2 1 2 2
2 1 3 3
1 2 6

Sample Output

7

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值