题目链接:http://poj.org/problem?id=3281
PS:刷够网络流了,先这样吧,之后再刷,慢慢补。
题意:有F种食物,D种饮料,N头奶牛,只能吃某种食物和饮料(而且只能吃特定的一份),一种食物被一头牛吃了之后,其余牛就不能吃了 第一行有N,F,D三个整数:接着2-N+1行代表第i头牛,前面两个整数是Fi与Di(食物与饮料的种类数量),接着是食物的种类与饮料的种类 要求输出最多分配能够满足的牛的数量.
思路:这是一种神奇的建图方式-拆点。让我想打死都想不出来。sad
建图,有2*n+f+d+2个顶点,0表示源点,2*n+f+d+1表示汇点。 由源点指向食物,再由食物指向牛,牛再指向对应的饮料,饮料再指向汇点 当然要使每一头牛都对应每一份食物与饮料,所以应该牛i指向牛i再指向饮料,这样就可以避免一头牛只占用多份食物与饮料了 全部是有向的边,而且权值全部为1 我在这里是1到f为食物点,f+1到f+2*n为牛点,f+2*n+1到f+2*n+d为饮料点
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <queue> #include <math.h> #define N 1100 #define inf 0x3f3f3f3f typedef int ll; using namespace std; ll n,f,d,tt,dis[N],head[N]; struct node {ll x,y,w,next; } eg[N*N]; void init() {tt=0;memset(head,-1,sizeof(head)); } void add(int xx,int yy) {eg[tt].x=xx;eg[tt].y=yy;eg[tt].w=1;eg[tt].next=head[xx];head[xx]=tt++;eg[tt].x=yy;eg[tt].y=xx;eg[tt].w=0;eg[tt].next=head[yy];head[yy]=tt++; } bool bfs(int s,int e) {memset(dis,-1,sizeof(dis));dis[s]=0;queue<int>q;q.push(s);while(!q.empty()){int fa=q.front();q.pop();for(int i=head[fa]; i!=-1; i=eg[i].next){int v=eg[i].y;if(dis[v]==-1&&eg[i].w){dis[v]=dis[fa]+1;q.push(v);}}}if(dis[e]>0)return true;return false; } int dinic(int s,int maxt) {if(s==2*n+f+d+1) return maxt;int a,sum=maxt;for(int i=head[s]; i!=-1; i=eg[i].next){int v=eg[i].y;if(dis[v]==dis[s]+1&&eg[i].w>0){a=dinic(v,min(sum,eg[i].w));eg[i].w-=a;eg[i+1].w+=a;sum-=a;}}return maxt-sum; } int main() {ll xx,yy,s1,s2;scanf("%d%d%d",&n,&f,&d);init();for(int j=1;j<=f;j++){add(0,j);}for(int j=1;j<=d;j++){add(f+2*n+j,f+2*n+d+1);}for(int i=1;i<=n;i++){scanf("%d%d",&s1,&s2);for(int j=1;j<=s1;j++){scanf("%d",&xx);add(xx,f+i);}for(int j=1;j<=s2;j++){scanf("%d",&yy);add(f+n+i,f+2*n+yy);}}for(int i=1;i<=n;i++){add(f+i,f+n+i);}ll ans=0;while(bfs(0,2*n+f+d+1)){ans+=dinic(0,inf);}printf("%d\n",ans);return 0; }