[POJ3281]Dining 最大流(建图奇葩)
2015-11-13 21:30
295 查看
题目链接:http://poj.org/problem?id=3281
参考了某犇做的PPT。对于此题的解释有如下内容(我只是搬运工)。
【题目大意】 有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。现在有N头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。(1 <= F <= 100, 1 <= D <= 100, 1 <= N <= 100)
此题的建模方法比较有开创性。以往一般都是左边一个点集表示供应并与源相连,右边一个点集表示需求并与汇相连。现在不同了,供应有两种资源,需求仍只有一个群体,怎么办?其实只要仔细思考一下最大流的建模原理,此题的构图也不是那么难想。最大流的正确性依赖于它的每一条s-t流都与一种实际方案一一对应。那么此题也需要用s-t流将一头牛和它喜欢的食物和饮料“串”起来,而食物和饮料之间没有直接的关系,自然就想到把牛放在中间,两边是食物和饮料,由s, t将它们串起来构成一种分配方案。至此建模的方法也就很明显了:每种食物i作为一个点并连边(s, i, 1),每种饮料j作为一个点并连边(j, t, 1),将每头牛k拆成两个点k’, k’’并连边(k’, k’’, 1), (i, k’, 1), (k’’, j, 1),其中i, j均是牛k喜欢的食物或饮料。求一次最大流即为结果。
(牛必须放中间嗯)dinic板子,代码如下:
参考了某犇做的PPT。对于此题的解释有如下内容(我只是搬运工)。
【题目大意】 有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。现在有N头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。(1 <= F <= 100, 1 <= D <= 100, 1 <= N <= 100)
此题的建模方法比较有开创性。以往一般都是左边一个点集表示供应并与源相连,右边一个点集表示需求并与汇相连。现在不同了,供应有两种资源,需求仍只有一个群体,怎么办?其实只要仔细思考一下最大流的建模原理,此题的构图也不是那么难想。最大流的正确性依赖于它的每一条s-t流都与一种实际方案一一对应。那么此题也需要用s-t流将一头牛和它喜欢的食物和饮料“串”起来,而食物和饮料之间没有直接的关系,自然就想到把牛放在中间,两边是食物和饮料,由s, t将它们串起来构成一种分配方案。至此建模的方法也就很明显了:每种食物i作为一个点并连边(s, i, 1),每种饮料j作为一个点并连边(j, t, 1),将每头牛k拆成两个点k’, k’’并连边(k’, k’’, 1), (i, k’, 1), (k’’, j, 1),其中i, j均是牛k喜欢的食物或饮料。求一次最大流即为结果。
(牛必须放中间嗯)dinic板子,代码如下:
#include <algorithm> #include <iostream> #include <iomanip> #include <cstring> #include <climits> #include <complex> #include <fstream> #include <cassert> #include <cstdio> #include <bitset> #include <vector> #include <deque> #include <queue> #include <stack> #include <ctime> #include <set> #include <map> #include <cmath> using namespace std; typedef struct Edge { int u, v, c, next; }Edge; const int inf = 0x7f7f7f7f; const int maxn = 2222; int cnt, head[maxn]; int cur[maxn], dd[maxn]; Edge edge[maxn<<1]; int N, F, D; int n[maxn], f[maxn], d[maxn]; int S, T; void init() { memset(head, -1, sizeof(head)); for(int i = 0; i < maxn; i++) edge[i].next = -1; S = 0; } void adde(int u, int v, int c, int c1) { edge[cnt].u = u; edge[cnt].v = v; edge[cnt].c = c; edge[cnt].next = head[u]; head[u] = cnt++; edge[cnt].u = v; edge[cnt].v = u; edge[cnt].c = c1; edge[cnt].next = head[v]; head[v] = cnt++; } bool bfs(int s, int t, int n) { queue<int> q; for(int i = 0; i < n; i++) dd[i] = inf; dd[s] = 0; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); for(int i = head[u]; ~i; i = edge[i].next) { if(dd[edge[i].v] > dd[u] + 1 && edge[i].c > 0) { dd[edge[i].v] = dd[u] + 1; if(edge[i].v == t) return 1; q.push(edge[i].v); } } } return 0; } int dinic(int s, int t, int n) { int st[maxn], top; int u; int flow = 0; while(bfs(s, t, n)) { for(int i = 0; i < n; i++) cur[i] = head[i]; u = s; top = 0; while(cur[s] != -1) { if(u == t) { int tp = inf; for(int i = top - 1; i >= 0; i--) { tp = min(tp, edge[st[i]].c); } flow += tp; for(int i = top - 1; i >= 0; i--) { edge[st[i]].c -= tp; edge[st[i] ^ 1].c += tp; if(edge[st[i]].c == 0) top = i; } u = edge[st[top]].u; } else if(cur[u] != -1 && edge[cur[u]].c > 0 && dd[u] + 1 == dd[edge[cur[u]].v]) { st[top++] = cur[u]; u = edge[cur[u]].v; } else { while(u != s && cur[u] == -1) { u = edge[st[--top]].u; } cur[u] = edge[cur[u]].next; } } } return flow; } int main() { // freopen("in", "r", stdin); while(~scanf("%d %d %d", &N, &F, &D)) { init(); T = 2 * N + F + D + 1; int ff, dd; //把牛的位置拆开,放在食物和饮料中间 //S指向食物,饮料指向T,牛指向牛 for(int i = 1; i <= F; i++) adde(S, i, 1, 0); for(int i = 1; i <= D; i++) adde(2*N+F+i, T, 1, 0); for(int i = 1; i <= N; i++) adde(F+i, F+N+i, 1, 0); //确定食物指向牛、牛指向饮料的关系 for(int i = 1; i <= N; i++) { int tmp; scanf("%d %d", &ff, &dd); for(int j = 0; j < ff; j++) { scanf("%d", &tmp); adde(tmp, F+i, 1, 0); } for(int j = 0; j < dd; j++) { scanf("%d", &tmp); adde(F+N+i, 2*N+F+tmp, 1, 0); } } printf("%d\n", dinic(S, T, T+1)); } return 0; }
相关文章推荐
- [bzoj4326][NOIP2015]运输计划
- 树状数组题目详解 HDU 1166 HDU 1541
- android背景设置报错 <item> tag requires a 'drawable' attribute or child tag defining a drawable
- WinPcap笔记(5):不用回调方法捕获数据包
- Spine的回调函数,以及简单运用
- tengine install
- ALM使用流程
- hdoj 1495 非常可乐 【bfs(互相倒水)】
- 【Unity实用小方法】开启游戏时播放一段动画
- 串的顺序存储结构
- 实现 implements后重写toString
- iOS如何提高tableView的性能
- 8)排序②排序算法之选择排序[1]直接选择排序
- Adaboost 算法的原理与推导
- plsql developer7.1.4 + instantclient_10_2 链接远程oracle数据库
- android 解决listview 内部有按键控件时,listview无法点击
- XMLDLL操作说明文档(一)
- MySQL, 创建一个只读用户和一个所有权限用户
- pdf转word工具
- hdu 1166 敌兵布阵【线段树】单点更新,区间求和