PIGS
Time Limit: 1000MS | Memory Limit: 10000K | |
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.
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.
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
————————————————————感慨的分割线————————————————————
前言:很多人在通向成功的路上走向了失败。
思考了两天怎样建图。发过誓不看题解的。昨天转变思想,以顾客为顶点建了一张图,但是WA了。于是放弃了这张图。到了今天实在没辙,看了一样题解的图,发现竟然就是以顾客为顶点的!我重新拿出那张图,却一连WA了3个小时。是在没办法我一行一行更改,终于发现是因为id写成了i。就这样,我把本可以完全凭借自己的力量解决的题目,诉诸于题解上的图是什么样子。和成功擦肩而过。今后再也不使用id这样的变量了。
思路:如果以猪圈为顶点,无论如何都是建不对图的。因为顾客才可以打开猪圈,这就意味着猪圈和猪圈之间的边时而存在,时而不存在。但是仔细观察,发现顾客之间的关系。
假如说A顾客打开了猪圈1,那么在他关闭猪圈之后,顾客C重新打开猪圈1,这个时候我要使猪圈1当中的猪尽量多。
也就是说,紧接着打开同一个猪圈之间的顾客之间存在边!
那么转变思路,以顾客为顶点。
倘若之前猪圈没有被打开过,就是从S -> 顾客C,容量就是该猪圈初始值
如果最后一个打开该猪圈的是顾客X,就是从顾客X -> 顾客C,容量是多少?
题目说每个猪圈容量无穷大,那么,顾客X能剩余多少猪,就可以卖多少猪,不妨设为INF
最后就是顾客C -> T,容量为想买的猪个数
之后一顿套模板。
代码如下:
/*
ID: j.sure.1
PROG:
LANG: C++
*/
/****************************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <string>
#include <climits>
#include <iostream>
#define INF 99999999
using namespace std;
/****************************************/
const int M = 1111, N = 111;
struct Node {
int u, v, c;
int next;
}edge[N*N];
int n, m, tot, S, T;
int head[N], lev[N], q[N], s[N], cur[N];
int pig[M], last[M];
void add(int u, int v, int c)
{
edge[tot].u = u; edge[tot].v = v; edge[tot].c = c;
edge[tot].next = head[u]; head[u] = tot++;
}
bool bfs()
{
int fron = 0, rear = 0;
memset(lev, -1, sizeof(lev));
lev[S] = 0;
q[rear++] = S;
while(fron < rear) {
int u = q[fron%N]; fron++;
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if(edge[i].c && lev[v] == -1) {
lev[v] = lev[u] + 1;
q[rear%N] = v; rear++;
if(v == T) return true;
}
}
}
return false;
}
int Dinic()
{
int ret = 0;
while(bfs()) {
memcpy(cur, head, sizeof(head));
int u = S, top = 0;
while(1) {
if(u == T) {
int mini = INF, loc;
for(int i = 0; i < top; i++) {
if(mini > edge[s[i]].c) {
mini = edge[s[i]].c;
loc = i;
}
}
for(int i = 0; i < top; i++) {
edge[s[i]].c -= mini;
edge[s[i]^1].c += mini;
}
ret += mini;
top = loc;//回溯
u = edge[s[top]].u;
}
int &i = cur[u];
for(; i != -1; i = edge[i].next) {
int v = edge[i].v;
if(edge[i].c && lev[u] + 1 == lev[v]) break;
}//找到允许弧
if(i != -1) {
s[top] = i; top++;
u = edge[i].v;
}
else {
if(top == 0) break;
lev[u] = -1;
top--; u = edge[s[top]].u;
}//找不到允许弧
}
}
return ret;
}
int main()
{
#ifdef J_Sure
// freopen("000.in", "r", stdin);
// freopen(".out", "w", stdout);
#endif
scanf("%d%d", &m, &n);
S = 0; T = n+1;
tot = 0;
memset(head, -1, sizeof(head));
for(int i = 1; i <= m; i++) {
scanf("%d", &pig[i]);//输入每个猪圈的猪
last[i] = 0;
}
int key, buy, room;
for(int i = 1; i <= n; i++) {
scanf("%d", &key);//顾客钥匙数
for(int j = 0; j < key; j++) {
scanf("%d", &room);//哪些钥匙
if(!last[room]) {
add(S, i, pig[room]);
add(i, S, 0);
}
else {
add(last[room], i, INF);
add(i, last[room], 0);
}
last[room] = i;
}
scanf("%d", &buy);//买几个猪
add(i, T, buy);
add(T, i, 0);
}
printf("%d\n", Dinic());
return 0;
}