题目:http://poj.org/problem?id=1149
不把猪圈当做点,而把顾客当作点,把猪当作边权(流量);
因为猪圈中的猪可流动,所以共用一个猪圈的人互相连边;
注意应该连成链的形式,来保证先后顺序。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; queue<int>q; int m,n,s[1005],head[150],ct=1,cur[150],hd[1005],inf=1e9,d[150],ans; bool sid[150][150]; struct N{ int to,next,w; N(int t=0,int n=0,int ww=0):to(t),next(n),w(ww) {} }edge[25000]; bool in[150]; void add(int x,int y,int z) { sid[x][y]=1;sid[y][x]=1; edge[++ct]=N(y,head[x],z);head[x]=ct; edge[++ct]=N(x,head[y],0);head[y]=ct; } int fd(int x,int y) { for(int i=head[y];i;i=edge[i].next)//此处为有向边,所以应找y边集中连到x的边! if(edge[i].to==x)return i; return 0; } bool bfs() { memset(d,0,sizeof d); while(q.size())q.pop(); d[0]=1;q.push(0); while(q.size()) { int x=q.front();q.pop(); for(int i=head[x];i;i=edge[i].next) { int u=edge[i].to; if(!d[u]&&edge[i].w) { d[u]=d[x]+1; q.push(u); } } } return d[n+1]; } int dfs(int x,int f) { if(x==n+1)return f; int res=0; for(int i=cur[x];i;i=edge[i].next) { int u=edge[i].to; if(d[u]==d[x]+1&&edge[i].w) { int tmp=dfs(u,min(edge[i].w,f-res)); edge[i].w-=tmp; edge[i^1].w+=tmp; res+=tmp; if(edge[i].w)cur[x]=i; if(res==f)return f; } } if(!res)d[x]=0; return res; } int main() { scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) scanf("%d",&s[i]); for(int i=1;i<=n;i++) { int k,x; scanf("%d",&k); for(int j=1;j<=k;j++) { scanf("%d",&x); if(!hd[x]&&!in[i])hd[x]=i,in[i]=1,add(0,i,s[x]); else if(!hd[x]&&in[i]) { hd[x]=i; int e=fd(i,0); edge[e].w+=s[x]; // edge[e^1].w-=s[x];//!!! } // if(!hd[x])hd[x]=i,add(0,i,s[x]); if(hd[x]) { if(!sid[hd[x]][i])//免重 add(hd[x],i,inf); hd[x]=i;//!!!成链 } } scanf("%d",&x); add(i,n+1,x); } while(bfs()) { for(int i=0;i<=n+1;i++)cur[i]=head[i]; ans+=dfs(0,inf); } printf("%d",ans); return 0; }