PIGS
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 24426 Accepted: 11127
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
题意:就是一个养猪户卖猪,有M个房间,猪在房间里锁着,但是自己身上没有钥匙,买猪的人有N个,每个人手上有A个钥匙,分别是K1,K2,K3。。。KA房间的钥匙,所以可以买这些房间里面的猪,买猪的人需要B头猪。每一次来买猪的人买完后,养猪户都可以把其中一些房间的猪赶到另外一些房间里面去,这些房间都是这次买猪的人能打开的,而且每一间的房间可以装无限多的猪。
当时少看了两个条件,去看博客的时候看题意才懂的,一个是可以赶猪,另一个就是按照顺序来买猪,不然就会2号买猪先买,然后把3房间的猪赶到2房间,然后所有人都可以买到猪了,与样例答案不符。所以这个是按照顺序来买猪的。
问总共可以卖多少头猪
样例解释:3个房间,分别3 1 10 头猪。
3个买猪人,第一个2个钥匙,能开1 2 房间,需要2头猪
后面不解释
然后可以养猪户总共卖了7头猪
首先第一个买猪,买了1房间两头猪,然后养猪户把1房间剩下的1头猪赶到2房间,此时2房间有2头猪
第二个买猪的买3房间3头猪
第三个买2房间的2头猪
总共7头
思路:网络流,从源点到每个买猪人建边,流量是需要的猪的数量,每个买猪到能开的房间建边,流量是原来房间猪的数量,房间到汇点建边,流量是原来房间猪的数量。
第一个不解释,第二个是原来房间猪的数量,意思是:因为赶猪的条件,每个房间的猪可能会赶到其他房间,后来的买猪人会买到这些猪,但是把猪的剩余数量流到其他房间显得不太可能,**于是我们可以把有相同钥匙(即能开同一房间)的人建一条边,流量是INF,**这样,我们就可以转换一下,既然你可以把猪都赶到一个房间,那么就可以赶到我们相同的房间,那么我想买多少头猪,就可以通过你的途径来买,于是这条边是后来的指向先到的,流量是INF,因为还有后来的可以通过我的途径然后我通过你的途径来买猪~~(禁止套娃)~~ 第三个不解释,然后网络流套板子就可以了。
AC代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstdio>
using namespace std;
const int maxm=5e5+10;
const int maxn=3000;
const int INF=0x7f7f7f7f;
struct Edge{
int next,v,val;
}map[maxm];
int head[maxn],sum;
int n,m,S,E,maxflow;
int num[maxn],dep[maxn],gap[maxn];
void Init()
{
memset(map,0,sizeof(map));
memset(head,-1,sizeof(head));
sum=0;
return ;
}
void addedge(int u,int v,int w)
{
map[sum].v=v;
map[sum].val=w;
map[sum].next=head[u];
head[u]=sum++;
map[sum].v=u;
map[sum].val=0;
map[sum].next=head[v];
head[v]=sum++;
return ;
}
void bfs()
{
memset(dep,-1,sizeof(dep));
memset(gap,0,sizeof(gap));
dep[E]=0;gap[0]=1;
queue<int> q;
q.push(E);
while (!q.empty())
{
int u=q.front();
q.pop();
for (int i=head[u];i!=-1;i=map[i].next)
{
int v=map[i].v;
if (dep[v]!=-1) continue;
q.push(v);
dep[v]=dep[u]+1;
gap[dep[v]]++;
}
}
//cout<<dep[S]<<"---------"<<endl;
return ;
}
int dfs(int u,int flow)
{
if (u==E)
{
maxflow+=flow;
//cout<<maxflow<<" --== ==-- "<<endl;
//cout<<dep[S]<<endl;
return flow;
}
int used=0;
for (int i=head[u];i!=-1;i=map[i].next)
{
int v=map[i].v;
if (map[i].val>0&&dep[v]+1==dep[u])
{
//cout<<u<<" -> "<<v<<" "<<map[i].val<<endl;
int meta=dfs(v,min(map[i].val,flow-used));
if (meta>0)
{
map[i].val-=meta;
map[i^1].val+=meta;
used+=meta;
}
if (used==flow) return used;
}
}
--gap[dep[u]];
if (gap[dep[u]]==0) dep[S]=E+1;
dep[u]++;
gap[dep[u]]++;
return used;
}
int ISAP()
{
maxflow=0;
bfs();
while (dep[S]<E) dfs(S,INF);
return maxflow;
}
int main(){
vector<int> bri[maxn];
int fl[maxn];
int w,k;
cin>>m>>n;
S=0;E=n+m+1;
Init();
for (int i=1;i<=m;i++){
scanf("%d",&fl[i]); //记录每个房间原来猪的数量
addedge(n+i,E,fl[i]); //房间和汇点建边
}
for (int i=1;i<=n;i++){
scanf("%d",&k);
for (int j=1;j<=k;j++) {
scanf("%d",&num[j]);
bri[num[j]].push_back(i); //记录可以打开房间的买猪人
}
scanf("%d",&w);
for (int j=1;j<=k;j++)
addedge(i,n+num[j],fl[num[j]]);//买猪人和房间建边
addedge(S,i,w); //源点和买猪人建边
}
for (int i=1;i<=m;i++){
k=bri[i].size();
for (int j=k-1;j>0;j--)
addedge(bri[i][j],bri[i][j-1],INF); //从后往前人人之间建边
}
int ans=ISAP();
cout<<ans<<endl;
return 0;
}