题意:
有m个猪圈,n个顾客,这些顾客按顺序购买,每个顾客有若干猪圈的钥匙,可以从其中购买猪,在一个顾客买完之后,可以将这个顾客可以打开的猪圈内的猪重新调整,问最多这些顾客能买走多少猪
算法:网路最大流
用顾客来作为节点,顾客数最多为100,时间和空间都可以达到要求。新增源点s,汇点t,对于每个顾客来说,如果他是第一个打开某猪圈的,则从s向他连一条容量为该猪圈初始值的边,如果与源点的流量已经不是0,则合并,如果不是第一个,则从上一个打开该猪圈的顾客向这个顾客连一条容量为+oo的边,每个顾客向汇点连一条容量为该顾客希望购买的猪的数量的边
首先按上面的方法构造一个容量网路,再从初始流(零流)出发进行标号,调整。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define INF 300000000 #define MAXM 1000 #define MAXN 100 int s,t; //源点,汇点 int customer[MAXN+2][MAXN+2];//各节点之间的容量 int flow[MAXN+2][MAXN+2]; //节点之间的流量 int i,j; void init() { int M,N; int num; int k; //第k个猪圈的钥匙 int house[MAXM] ; //储存每个猪圈中猪的个数 int last[MAXM]; //储存每个猪圈的前一个顾客的钥匙数 memset(last,0,sizeof(last)); memset(customer,0,sizeof(customer)); scanf("%d%d",&M,&N); s=0; t=N+1; for(i=1; i<=M; i++) scanf("%d",&house[i]); for(i=1; i<=N; i++) { scanf("%d",&num); for(j=0; j<num; j++) { scanf("%d",&k); if(last[k]==0) customer[s][i]=customer[s][i]+house[k]; else customer[last[k]][i]=INF; last[k]=i; } scanf("%d",&customer[i][t]); } } void ford() { int prev[MAXN+2]; int minflow[MAXN+2]; int queue[MAXN+2]; int qs,qe; int v; int p; for(i=0; i<MAXN+2; i++) { for(j=0; j<MAXN+2; j++) { flow[i][j]=0; } } minflow[0]=INF; while(1) { for(i=0; i<MAXN+2; i++) prev[i]=-2; prev[0]=-1; qs=0; queue[qs]=0; qe=1; while(qe>qs&&prev[t]==-2) { v=queue[qs]; qs++; for(i=0; i<t+1; i++) { if(prev[i]==-2&&(p=customer[v][i]-flow[v][i])) { prev[i]=v; queue[qe]=i; qe++; minflow[i]=(minflow[v]<p)?minflow[v]:p; } } } if(prev[t]==-2) break; for(i=prev[t],j=t;i!=-1;j=i,i=prev[i]) { flow[i][j]=flow[i][j]+minflow[t]; flow[j][i]=-flow[i][j]; } } p=0; for(i=0;i<t;i++) { p=p+flow[i][t]; } printf("%d ",p); } int main() { init(); ford(); return 0; }