题面(来源于HLOJ)
题目描述
尼克在一家养猪场工作,这家养猪场共有M间锁起来的猪舍,由于猪舍的钥匙都给了客户,所以尼克没有办法打开这些猪舍,客户们从早上开始一个接一个来购买生猪,他们到达后首先用手中的钥匙打开他所能打开的全部猪舍,然后从中选取他要买的生猪,尼克可以在此期间将打开的猪舍中的猪调整到其它开着的猪舍中,每个猪舍能存放的猪的数量是没有任何限制的。买完猪后客户会将他打开的猪舍关上。
好在尼克事先知道每位客户手中有哪些钥匙,要买多少猪,以及客户到来的先后次序。请你写一个程序,帮助尼克求出最多能卖出多少头生猪。
输入格式
输入文件的第一行包含两个整数M和N,1≤M≤1000,1≤N≤100,M为猪舍的数量,N为客户人数,猪舍的编号为1到M,客户的编号为1到N。
输入文件第二行包含M个空格隔开的整数,依次表示每个猪舍中的生猪数量,每个整数大于等于0,且小于等于1000。
接下来的N行每行表示一位客户的购买信息,第I个客户的购买信息位于第I+2行,
其格式如下:
A K1 K2……KA B
它表示该客户共有A把钥匙,钥匙编号依次为K1 K2……KA,且K1< K2<……< KA,B为该客户要买的生猪的头数。
输出格式
输出文件仅有一行包含一个整数,表示尼克最多能卖出的生猪的头数。
题解
经典的网络流问题。
我们先想一想,猪的流动。总体流动方向是从猪圈流到客户手中,所以我们可以建立一个超级源点S,并连接S到所有猪圈的边,容量为猪圈初始猪的数量;建立一个超级汇点T,并连接所有客户到T的边,容量为客户希望买到的猪的数量。
继续思考,每一个客户打开猪圈后,这些猪可以乱跑,所以下一位客户只要在上一个客户打开的猪圈里任意打开一个,就可以买到上一位客户打开的猪圈里所有的猪。
所以我们可以 继续连边:对于任意一个猪圈,向第一个打开它的客户连一条INF的边,对于任意一个猪圈,每一个客户都向紧接着打开该猪圈的下一个客户连一条INF的边。
这样做一遍dinic最大流就行了。
要命的梗
数组越界果然什么都会出来。我因为数组越界,先wa后tle。。
code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int num=0;char c=' ';bool flag=true;
for(;c>'9'||c<'0';c=getchar())
if(c=='-')
flag=false;
for(;c>='0'&&c<='9';num=(num<<3)+(num<<1)+c-48,c=getchar());
return flag ? num : -num;
}
namespace graph{
const int INF=0x7FFFFFFF;
const int maxn=5200,maxm=1020;
struct node{
int y,val,next;
}a[(maxn+maxm+maxm*maxm)<<1];
int head[maxm],top=0,m,n;
void insert(int x,int y,int v){
a[top].y=y;
a[top].val=v;
a[top].next=head[x];
head[x]=top++;
}
int pre[maxm],s,t;
void init(){
memset(head,-1,sizeof head);
m=read();n=read();
s=0;t=n+m+1;
for(int i=1;i<=m;i++){
int x=read();
insert(s,i,x);
insert(i,s,0);
}//源点向所有猪圈连边
for(int i=1;i<=n;i++){
int num=read();
for(int j=1;j<=num;j++){
int x=read();
if(pre[x])insert(pre[x],i+m,INF),insert(i+m,pre[x],0);
else insert(x,i+m,INF),insert(i+m,x,0);
//猪圈向第一个客户连边
//每一客户向下一个紧接着打开该猪圈的客户连边
pre[x]=i+m;
}
int want=read();
insert(i+m,t,want);
insert(t,i+m,0);
//客户向汇点连边
}
}
}using namespace graph;
namespace MAX_flow{//下面就是一个裸最大流
//带当前弧优化的dinic算法
int d[maxn],cur[maxn];
bool bfs(){
memset(d,0,sizeof d);
queue<int>q;
q.push(s);
d[s]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=a[i].next){
int v=a[i].y;
if(a[i].val==0||d[v])continue;
d[v]=d[u]+1;
q.push(v);
if(v==t)return true;
}
}
return false;
}
int dfs(int x,int flow){
if(x==t)return flow;
for(int &i=cur[x];i!=-1;i=a[i].next){//当前弧优化
int y=a[i].y;
if(a[i].val==0||d[y]!=d[x]+1)continue;
int k=dfs(y,min(flow,a[i].val));
if(k>0){
a[i].val-=k;
a[i^1].val+=k;
return k;
}
}
return 0;
}
}using namespace MAX_flow;
int main(){
init();
int ans=0;
while(bfs()){
for(int i=s;i<=t;i++)
cur[i]=head[i];
while(int flow=dfs(0,INF))
ans+=flow;
}
printf("%d\n",ans);
return 0;
}