您的位置:首页 > 其它

[POJ1149]PIGS 做题笔记

2016-03-03 17:20 239 查看
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

这题的一个技巧:网络流的+oo容量边可以传递流量。

除了每个猪圈的第一个顾客,每个猪圈的顾客都可以获得这个猪圈的上一个顾客所能获得的所有的猪,因为上一个顾客来了后,在极端情况下可以把他所能获得的所有的猪都调到当前顾客光顾的猪圈。

有了这个思路,我们新建超级源汇,S到第一个光顾某猪圈的顾客连一条容量为该猪圈初始猪数目的边,如果这个顾客还能光顾其它猪圈并且这些猪圈也是第一次有人光顾,那么可以把这些边合并。

如果一个猪圈有人光顾了,那么从这个猪圈的上一个顾客到这个猪圈的当前顾客连一条容量+oo的边。

所有的顾客到T连容量为顾客要买的猪的数量的边。

然后跑一遍最大流。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N=200,M=30000,inf=0x3fffffff;
int pig[2000],last[2000];
int head
,d
,e[M],ver[M],next[M];
int tot=1,n,m,maxflow=0,s,t;

void add (int u,int v,int w) {
ver[++tot]=v;e[tot]=w;next[tot]=head[u];head[u]=tot;
ver[++tot]=u;e[tot]=0;next[tot]=head[v];head[v]=tot;
}

bool bfs () {
queue<int> q;
memset(d,0,sizeof(d));
q.push(s); d[s]=1;
while (!q.empty()) {
int x=q.front(); q.pop();
for (int i=head[x];i;i=next[i])
if (e[i]&&!d[ver[i]]) {
q.push(ver[i]);
d[ver[i]]=d[x]+1;
if (ver[i]==t) return 1;
}
}
return 0;
}

int dinic (int x,int f) {
int rest=f;
if (x==t) return f;
for (int i=head[x];i&&rest;i=next[i])
if (e[i]&&d[ver[i]]==d[x]+1) {
int now=dinic(ver[i],min(e[i],rest));
if (!now) d[ver[i]]=0;//
e[i]-=now;
e[i^1]+=now;
rest-=now;
}
return f-rest;
}

int main () {
int k,x,w,tmp;
scanf("%d%d",&m,&n);
s=0;t=n+1;
for (int i=1;i<=m;i++)
scanf("%d",&pig[i]);
for (int i=1;i<=n;i++) {
scanf("%d",&k);
tmp=0;
for (int j=1;j<=k;j++) {
scanf("%d",&x);
if (!last[x]) tmp+=pig[x];
else add(last[x],i,inf);
last[x]=i;
}
scanf("%d",&w);
if (tmp) add(s,i,tmp);
add(i,t,w);
}
while (bfs())
while (tmp=dinic(s,inf)) maxflow+=tmp;
printf("%d",maxflow);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: