POJ 3281 Dining 题解
2016-01-20 16:53
162 查看
【题意】:
有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。
【分析】:
这是一道匹配问题,我们可以用网络流建模来解决。
先考虑建立食物—牛—饮料的图,即:
1):源点S向每种食物连容量为1的有向边
2):每种食物向对应的牛(喜欢吃该食物的牛)连容量为1的有向边
3):每头牛向喜欢喝的饮料连容量为1的有向边
4):每种饮料向汇点T连容量为1的有向边
这种建模方式,思考一下,每种食物或饮料的确是只能供一头牛享用,因为受到了S到食物和饮料到T的容量1的限制,使得每个饮料和食物都只被用一次,但是,仔细想来,并未满足每头牛只享用一种食物和一种饮料。因为某头牛可能喜欢吃多种食物和饮料,而那头牛之前可能之前已匹配过一种食物和一种饮料,但可能存在之后的某次增广过程,是从那头牛喜欢吃的另一种食物进入牛这个点,且能从另一种饮料到达T,从而完成一次增广。
因而,我们还需加一类边:
5):将每头牛拆成入点和出点,入点到出点连一条容量为1的有向边
这样,就能满足“每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料”这两个条件了。
【代码】:
有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。
【分析】:
这是一道匹配问题,我们可以用网络流建模来解决。
先考虑建立食物—牛—饮料的图,即:
1):源点S向每种食物连容量为1的有向边
2):每种食物向对应的牛(喜欢吃该食物的牛)连容量为1的有向边
3):每头牛向喜欢喝的饮料连容量为1的有向边
4):每种饮料向汇点T连容量为1的有向边
这种建模方式,思考一下,每种食物或饮料的确是只能供一头牛享用,因为受到了S到食物和饮料到T的容量1的限制,使得每个饮料和食物都只被用一次,但是,仔细想来,并未满足每头牛只享用一种食物和一种饮料。因为某头牛可能喜欢吃多种食物和饮料,而那头牛之前可能之前已匹配过一种食物和一种饮料,但可能存在之后的某次增广过程,是从那头牛喜欢吃的另一种食物进入牛这个点,且能从另一种饮料到达T,从而完成一次增广。
因而,我们还需加一类边:
5):将每头牛拆成入点和出点,入点到出点连一条容量为1的有向边
这样,就能满足“每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料”这两个条件了。
【代码】:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; #define MAXNODE 402 #define MAXE 4610 #define IMAX 214748364 struct EDGE{int f,t,next,flow;}a[MAXE]; int N,F,D,tot=0,last[MAXNODE],ans=0,S,T; int d[MAXNODE],Q[MAXE]; bool map[MAXNODE][MAXNODE]; void add(int from,int to,int flow) { a[tot].t=to; a[tot].flow=flow; a[tot].next=last[from]; last[from]=tot++; a[tot].t=from; a[tot].flow=0; a[tot].next=last[to]; last[to]=tot++; } bool build() { int right=0; for(int i=S;i<=T;i++) d[i]=IMAX; d[S]=0; Q[++right]=S; for(int left=1;left<=right;left++) { int now=Q[left]; for(int i=last[now];i!=-1;i=a[i].next) { int to=a[i].t; if(a[i].flow && d[now]+1<d[to]) { d[to]=d[now]+1; if(to==T) return true; Q[++right]=to; } } } return false; } int DINIC(int now,int flow) { if(!flow) return 0; if(now==T) return flow; int rem=flow,use; for(int i=last[now];i!=-1;i=a[i].next) { int to=a[i].t; if(d[to]==d[now]+1 && (use=DINIC(to,min(flow,a[i].flow)))) { a[i].flow-=use; a[i^1].flow+=use; flow-=use; } } if(rem==flow) d[now]=-1; return rem-flow; } void MaxFlow() { int use; while(build()) { while(use=DINIC(S,IMAX)) ans+=use; } } int main() { //freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); memset(last,-1,sizeof(last)); scanf("%d%d%d",&N,&F,&D); S=0;T=F+2*N+D+1; for(int i=1;i<=F;i++) add(S,i,1); for(int i=1;i<=N;i++) add(F+i,F+N+i,1); for(int i=1;i<=D;i++) add(F+2*N+i,T,1); for(int i=1;i<=N;i++) { int f,d; scanf("%d%d",&f,&d); for(int j=1;j<=f;j++) { int foodnum; scanf("%d",&foodnum); if(!map[foodnum][F+i]) { add(foodnum,F+i,1); map[foodnum][F+i]=true; } } for(int j=1;j<=d;j++) { int drinknum; scanf("%d",&drinknum); if(!map[F+N+i][F+2*N+drinknum]) { add(F+N+i,F+2*N+drinknum,1); map[F+N+i][F+2*N+drinknum]=true; } } } MaxFlow(); printf("%d\n",ans); return 0; }
相关文章推荐
- 1014. 福尔摩斯的约会 (20)
- CodeForces 333A Secrets 题解&代码
- T-SQL 如何批量修改/转移大数据量数据.
- 下拉刷新框架android-Ultra-Pull-To-Refresh示例
- python升级2.7
- angular js表单验证
- Oracle 11g 在备份导出时缺少表的问题
- 几个常用T_SQL语句比较
- 网络图片放大缩小
- leetcode之 climbing stairs
- 蓝桥杯 比酒量(暴力搜索)
- 【struts2】action中使用通配符
- ionic cordova 常用命令
- linux下使用github和git
- 移位运算符中关于java编程思想中关于后侧的5个低位的意思:
- Android通过WebView选择文件上传(支持直接调起相机等应用)
- Java的浅拷贝和深拷贝
- Android学习历程4-Android实现网络多线程断点续传下载
- ios9-NSLayoutAnchor和UILayoutGuide实现自动布局
- 时序(转载)