POJ
来源:互联网 发布:开源电商平台 java 编辑:程序博客网 时间:2024/05/16 15:06
题目链接: POJ - 3281
题目大意
n头牛, f种食物, d种饮料, 每头牛有若干种喜欢的食物和若干种喜欢的饮料, 每种食物或饮料只能使用一次, 求最多能让多少头牛同时吃上喜欢的一个食物和一个饮料
思路
建图, 最大流
建图方法
- 将每种食物f拆成两个节点f1, f2, 从f1向f2连一条容量为1的边, 以保证每个食物只能用一次
- 饮料同样做拆分处理成d1, d2
- 每个牛c也拆分成c1, c2, 从c1向c2练一条容量为1的边, 以保证最后得到的最大流是一个食物-一个牛-一个饮料这样的路径组成的(保证最后的结果是同时吃上喜欢的食物和饮料的牛数)
- 如果一头牛c喜欢食物f, 连边f2->c1, 容量为1
- 如果一头牛c喜欢饮料d, 连边c2->d1, 容量为1
- 图中所有食物的第一个节点是源点, 所有饮料的第二个节点是汇点, 设置一个超级源点S和一个超级汇点T, 连接所有S->f1, d2->T, 容量为1
代码
#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <queue>#include <vector>using namespace std;const int MAXV = 1100, INF = 0X3F3F3F3F;struct edge{ int to, cap, rev; edge(int a, int b, int c) :to(a), cap(b), rev(c){}};vector<edge> G[MAXV];int iter[MAXV], level[MAXV], S, T;void add_edge(int from, int to, int cap){ G[from].push_back(edge(to, cap, G[to].size())); G[to].push_back(edge(from, 0, G[from].size()-1));}bool bfs(){ memset(level, -1, sizeof(level)); level[S] = 0; queue<int> que; que.push(S); while(!que.empty()) { int v = que.front(); que.pop(); for(int i=0; i<(int)G[v].size(); ++i) { edge &e = G[v][i]; if(e.cap>0 && level[e.to]==-1) { level[e.to] = level[v] + 1; que.push(e.to); } } } return level[T]!=-1;}int dfs(int v, int f){ if(v == T) return f; for(int &i=iter[v]; i<(int)G[v].size(); ++i) { edge &e = G[v][i]; if(e.cap>0 && level[e.to]>level[v]) { int d = dfs(e.to, min(f, e.cap)); if(d) { e.cap -= d; G[e.to][e.rev].cap+= d; return d; } } } return 0;}int max_flow(){ int flow = 0; while(bfs()) { memset(iter, 0, sizeof(iter)); int f; while((f=dfs(S, INF))) flow += f; } return flow;}int n, f, d, nf, nd, x;int main(){ while(scanf("%d%d%d", &n, &f, &d) == 3) { S = 0; int sum = n + f + d; T = 2*sum+1; for(int i=1; i<=sum; ++i) add_edge(i, i+sum, 1);//将牛, 食物, 饮料拆分成两个节点并连边 for(int i=1; i<=n; ++i) { scanf("%d%d", &nf, &nd); for(int j=0; j<nf; ++j) { scanf("%d", &x); add_edge(sum+n+x, i, 1);//食物和牛 } for(int j=0; j<nd; ++j) { scanf("%d", &x); add_edge(sum+i, n+f+x, 1);//牛和饮料 } } for(int i=n+1; i<=n+f; ++i) add_edge(S, i, 1);//超级源点 for(int i=sum+n+f+1; i<T; ++i) add_edge(i, T, 1);//超级汇点 printf("%d\n", max_flow()); for(int i=0; i<MAXV; ++i) G[i].clear(); } return 0;}
阅读全文
0 0
- POJ
- poj
- POJ
- POJ
- poj
- poj
- POJ
- POJ
- poj
- POJ
- POJ
- POJ
- POJ
- POJ
- POJ
- POJ
- POJ
- POJ
- 2017杭电ACM集训队单人排位赛
- LeetCode周练Contest-39代码解析(C++)
- Android Scroller学习笔记
- ubuntu远程控mac
- C语言字符串相关库函数
- POJ
- linux中的strip命令简介------给文件脱衣服
- 有关java多线程
- 一,零基础学习JavaScript-JavaScript简介(0)
- js检测当前使用的浏览器
- java项目编码格式转换(如GBK转UTF-8)
- LeetCode | 55. Jump Game
- 《程序员的自我修养》阅读笔记 --编译和链接
- Git常用操作总结