2012/2/25 更新。
题意:
每只牛有他喜欢的食物和饮料,问怎样匹配可以使能吃到满意的食物和饮料的牛的数量最大。
思路:
匹配问题。最大流的应用。难点在构图。
我对最大流的理解就是:应用在匹配,关键就是利用边的占用,每一条增广路对边都有一定的占用,每个匹配就类似一次占用。
所以只要在构图的时候牛在中间,食物在左边,饮料在右边,源点s连着食物,汇点t连着饮料,每条边权值都为1。
这样就可以保证每个食物和牛的唯一匹配,且每个饮料对牛的唯一匹配。
但是此时有个问题,就是对牛没有约束,实际上每只牛对食物或者饮料都是唯一的,就是一只牛不能匹配多个食物。
所以将牛进行拆点,拆成两个点,此两点中间有一条权值为1的边。这样就保证匹配唯一性。
#include<iostream> #include<vector> #include<string> #include<queue> #include<algorithm> #define llong long long #define Min(a,b) (a<b?a:b) #define Max(a,b) (a>b?a:b) #define Abs(a) ((a)>0?(a):-(a)) #define Mod(a,b) (((a)-1+(b))%(b)+1) using namespace std; const int N=405; const int M=60005; const int inf=1e10; int n,fd,dk; struct { int v,re,next,w; }edge[M]; int edgehead[N]; bool vis[N]; int level[N]; int k; void addedge(int u ,int v,int w) { edge[k].v=v; edge[k].w=w; edge[k].re=k+1; edge[k].next=edgehead[u]; edgehead[u]=k++; edge[k].v=u; edge[k].re=k-1; edge[k].w=0; edge[k].next=edgehead[v]; edgehead[v]=k++; } bool bfs(int s,int t) { memset(vis,0,sizeof(vis)); memset(level,0,sizeof(level)); vis[s]=true; level[s]=0; queue<int> que; que.push(s); while(!que.empty()) { int now=que.front(); que.pop(); if(now==t) return true; for(int i=edgehead[now];i;i=edge[i].next) { int v=edge[i].v; int w=edge[i].w; if(!vis[v]&&w) { level[v]=level[now]+1; vis[v]=true; que.push(v); } } } return false; } int dinic(int now,int sum,int t) { if(now==t) return sum; int os=sum; for(int i=edgehead[now];i && sum>0;i=edge[i].next) { int v=edge[i].v; int w=edge[i].w; if(level[v]==level[now]+1 && w) { int tmp=dinic(v,Min(w,sum),t); edge[i].w-=tmp; edge[edge[i].re].w+=tmp; sum-=tmp; } } return os-sum; } void solve(int s,int t) { int ans=0; while(bfs(s,t)) ans+=dinic(s,inf,t); printf("%d\n",ans); } int main() { scanf("%d%d%d",&n,&fd,&dk); int tmp1,tmp2; k=1; for(int i=1;i<=n;i++) { scanf("%d%d",&tmp1,&tmp2); int v; for(int j=1;j<=tmp1;j++) { scanf("%d",&v); addedge(v+n*2,i,1); } for(int j=1;j<=tmp2;j++) { scanf("%d",&v); addedge(i+n,v+n*2+fd,1); } } for(int i=1;i<=n;i++) addedge(i,n+i,1); int s=2*n+fd+dk+1; int t=s+1; for(int i=1;i<=fd;i++) addedge(s,2*n+i,1); for(int i=1;i<=dk;i++) addedge(2*n+fd+i,t,1); solve(s,t); return 0; }