这个题目我敲了一个简单的EK,这不是难点
难点在于建图,按题目的要求 每个猪圈和顾客都建点的话,那也太多了。。。我看了Edelweiss里面的缩点方法才建好的图,哎,惭愧啊
实际那些猪圈根本不需要单独建点,猪圈无非就是向顾客输送流量 以及向同时开着的猪圈输送流量,这一步可以直接缩为,当某个猪圈被第一次打开,它里面的流量就全部输送给那个顾客那个点,而且可以叠加,因为每一次猪圈是可以互通的,而且猪圈本身是没有容量限制,如果有限制,那就还得再考虑。
此外,每次对猪圈的接下来的访问者都进行建边。用来输送之后的流量
处理好初始点和结束点。
#include <iostream> #include <cstdio> #include <cstring> #define INF 1<<30 using namespace std; int m,n; int pigs[1010],cap[110][110],f[110][110],vis[1010][110],buys; int inq[1010],cnt[1010]; void init(){ memset(cap,0,sizeof cap); memset(f,0,sizeof cap); memset(vis,0,sizeof vis); memset(inq,0,sizeof inq); memset(cnt,0,sizeof cnt); } int ans,q[110],a[110],p[110]; void ek() { ans=0; const int M=105; for (;;){ memset(a,0,sizeof a); int head,rear; head=rear=0; a[0]=INF; q[rear++]=0; while(head!=rear){ int u=q[head++]; if (head>=M) head%=M; for (int v=0;v<=n+1;v++) if (!a[v] && cap[u][v]>f[u][v]){ p[v]=u; q[rear++]=v; if (rear>=M) rear%=M; a[v]=min(a[u],cap[u][v]-f[u][v]); } } if (a[n+1]==0) break; for (int u=n+1;u!=0;u=p[u]){ f[p[u]][u]+=a[n+1]; f[u][p[u]]-=a[n+1]; } ans+=a[n+1]; } } int main() { while (scanf("%d%d",&m,&n)!=EOF) { init(); int tmp,a; for (int i=1;i<=m;i++) scanf("%d",&pigs[i]); for (int i=1;i<=n;i++){ scanf("%d",&tmp); for (int j=0;j<tmp;j++){ scanf("%d",&a); vis[a][cnt[a]++]=i; if (inq[a]) continue; inq[a]=1; cap[0][i]+=pigs[a]; } scanf("%d",&buys); cap[i][n+1]=buys; } for (int i=1;i<=m;i++){ for (int j=0;j<cnt[i]-1;j++){ int a=vis[i][j]; int b=vis[i][j+1]; cap[a][b]=INF; } } } ek(); printf("%d\n",ans); } return 0; }
POJ 1149 网络流 合并建图,布布扣,bubuko.com
原文:http://www.cnblogs.com/kkrisen/p/3708038.html