题意:
你m个猪圈以及每个猪圈里原来有多少头猪,先后给你n个人,每个人能打开某一些猪圈并且他们最多想买Ki头猪,在每一个人买完后能将打开的猪圈中的猪顺意分配在这次打开猪圈里,在下一个人来之前 已打开的猪圈会被锁上。
问最多能卖几头猪
分析:
这个题明着想呢,肯定是要建N排点的,表示相同的猪圈的点连inf边,跑最大流的。
建那么多点肯定是会炸的。
在网络流中呢,如果我们做题的初步思路是最大流,那么肯定要将题目中问的直接问题抽象成水流,比如这道题,问最多的卖猪数,我们当然就要把猪的数量作为“流”,这是大家心照不宣的。
所谓建图呢?个人认为,网络流最终要的是“限制”二字,网络流的流量和连边就是一个个限制问题,所以我们要参透题目中给的限制问题,有时并不必要把图中的每一个关系都建边。
像这个题目中,猪圈里猪的数量是限制,每个人能打开的猪圈也是限制,买家的先后顺序也是限制,买猪的数量也是限制。所以我们只需要用这些限制构建模型,开始:
源点到每个猪圈来买的第一个人连一条容量为该猪圈里猪的数量的边(这个满足了第一、二个限制)
对于每个猪圈,第i个来买的人向第i+1个来买的人连一条容量为正无穷的边(这个满足了第三个限制)
每个人向汇点连一条容量为购买数量的边(这个满足了第四个限制)
网络流就是这样,严密合理得像一个故事一样。
一头猪,从猪圈出来经过几人之手最终被某个人买走,完成了他的使命。一单位流量从原点,流经一些人,最终流向汇点,也完成了它的使命。这边是对网络流的感性理解。
代码:
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<queue> 6 #include<cmath> 7 #define ms(a,x) memset(a,x,sizeof(a)) 8 using namespace std; 9 const int N=105,M=1005,inf=1e9; 10 struct node{int y,z,nxt;}e[N*M*2]; 11 int n,m,S,T,pg[M],nw[M],c=1; 12 int q[N],h[N],d[N],vis[N]; 13 void add(int x,int y,int z){ 14 e[++c]=(node){y,z,h[x]};h[x]=c; 15 e[++c]=(node){x,0,h[y]};h[y]=c; 16 } bool bfs(){ 17 int f=0,t=0;ms(d,-1); 18 q[t++]=S;d[S]=0; 19 while(f<t){ 20 int x=q[f++]; 21 for(int i=h[x],y;i;i=e[i].nxt) 22 if(d[y=e[i].y]==-1&&e[i].z) 23 d[y]=d[x]+1,q[t++]=y; 24 } return (d[T]!=-1); 25 } int dfs(int x,int f){ 26 if(x==T) return f;int w,tmp=0; 27 for(int i=h[x],y;i;i=e[i].nxt) 28 if(d[y=e[i].y]==d[x]+1&&e[i].z){ 29 w=dfs(y,min(f-tmp,e[i].z)); 30 if(!w) d[y]=-1; 31 e[i].z-=w;e[i^1].z+=w; 32 tmp+=w;if(tmp==f) return f; 33 } return tmp; 34 } int dinic(){ 35 int tot=0; 36 while(bfs()) tot+=dfs(S,inf); 37 return tot; 38 } int main(){ 39 scanf("%d%d",&m,&n);S=0;T=n+1; 40 for(int i=1;i<=m;i++) 41 scanf("%d",&pg[i]); 42 for(int i=1;i<=n;i++){ 43 int a,b,x;scanf("%d",&a); 44 while(a--){ 45 scanf("%d",&x); 46 if(!nw[x]) add(S,i,pg[x]),nw[x]=i; 47 else add(nw[x],i,inf),nw[x]=i; 48 } scanf("%d",&b);add(i,T,b); 49 } printf("%d",dinic()); 50 return 0; 51 }