POJ3281 Dining [最大流应用]

来源:互联网 发布:投诉淘宝小二判决电话 编辑:程序博客网 时间:2024/05/21 07:10

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;}


原创粉丝点击