经典的网络流题目,需要拆点再合并边和点 详细解题报告请看这位大牛的: http://imlazy.ycool.com/post.2059102.html 代码: #include<iostream> using namespace std; #define inf 999999 int f[105][105],cap[105][105]; int pre[105],q[105],rc[105],num[1001],u[1005];//u[i],记录第一个打开第i个猪笼的顾客,0表示还没有打开过 int n,m,ans; bool bfs() { int i,j,head=0,tail=1; memset(rc,0,sizeof(rc)); rc[0]=inf; pre[0]=-1; q[tail]=0; while(head<tail) { i=q[++head]; for(j=1;j<=n+1;j++) { if(cap[i][j]>f[i][j]&&!rc[j]) { rc[j]=rc[i]; if(cap[i][j]-f[i][j]<rc[j]) rc[j]=cap[i][j]-f[i][j]; pre[j]=i; q[++tail]=j; if(j==n+1) return true; } } } return false; } void update() { for(int i=n+1;i!=0;i=pre[i]) { f[pre[i]][i]+=rc[n+1]; f[i][pre[i]]=-f[pre[i]][i]; } ans+=rc[n+1]; } void EK() { while(bfs()) update(); } int main() { int i,j,k,t,max; while(scanf("%d%d",&m,&n)!=EOF) { memset(f,0,sizeof(f)); memset(cap,0,sizeof(cap)); memset(u,0,sizeof(u)); max=-1; for(i=1;i<=m;i++) scanf("%d",&num[i]); for(i=1;i<=n;i++) { scanf("%d",&k); if(k>max) max=k; for(j=1;j<=k;j++) { scanf("%d",&t); if(!u[t]) { u[t]=i; cap[0][i]+=num[t]; } else { cap[u[t]][i]=inf; } } scanf("%d",&k); cap[i][n+1]=k; } ans=0; EK(); printf("%d/n",ans); } return 0; }