圆桌问题[网络流24题之5]
2016-05-20 11:03
369 查看
问题描述:
假设有来自 n 个不同单位的代表参加一次国际会议。每个单位的代表数分别为 ri,i=1,2,...,n 。会议餐厅共有 m 张餐桌,每张餐桌可容纳 ci,(i=1,2,...,m) 个代表就餐。为了使代表们充分交流, 希望从同一个单位来的代表不在同一个餐桌就餐。 试设计一个算法,给出满足要求的代表就餐方案。编程任务:
对于给定的代表数和餐桌数以及餐桌容量,编程计算满足要求的代表就餐方案。数据输入:
第 1 行有 2 个正整数 m 和 n , m 表示单位数, n 表示餐桌数, 1<=m<=150,1<=n<=270 。第 2 行有 m 个正整数,分别表示每个单位的代表数。第 3 行有 n 个正整数,分别表示每个餐桌的容量。结果输出 :
如果问题有解,在第 1 行输出 1 ,并在接下来的 m 行给出每个单位代表的就餐桌号。(如果有多个满足要求的方案,只要输出 1 个方案。)否则就在第 1 行输出 0 。输入文件示例 :
4 54 5 3 5
3 5 2 6 4
输出文件示例:
11 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5
分析:
这个题目因为对于每一个单位只能在不同的餐桌就餐,所以我们可以在每一个单位到每一个餐桌之间连一条容量为 1 的有向边。下面给出构建图 N 过程:1 :新增一个源 S 和一个汇 T
2 :在 S 与每一个单位之间 i 连接一条容量为 ri 的有向边
3 :在每一个单位 i 与每一个餐桌 j 之间连接一条容量为 1 的有向边
4 :在每一个餐桌 j 与 T 连接一条容量为 ci 的有向边
然后求图 N 的最大流,如果从源 S 出发的每一条边全部满载的话问题就有解(便全部满载表示每一个代表都有一个座位),否则问题就无解。至于在有解时打印方案的话可以直接在图 N 中遍历每一个单位 i ,有流量的边连向的餐桌就表示有有一个代表在哪个餐桌就餐。
题目方案不唯一,推荐一个不需要打印方案的评测网站:http://oi.nks.edu.cn/
代码:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; int n,m; int ans; int tot=1; int head[447],nxt[147147],to[147147],wei[147147]; int cur[447]; int c[447]; int que[447]; int read(); void add(int,int,int); bool bfs(); bool dinic(int); int main(){ n=read();m=read(); for(int i=1,a;i<=n;++i){ a = read(); ans += a; add(1,i+1,a); } for(int i=1,a;i<=m;++i){ a = read(); add(i+n+1,n+m+2,a); } for(int i=1;i<=n;++i) for(int j=m;j>=1;--j) add(i+1,j+n+1,1); while(bfs()){ memcpy(cur,head,sizeof head); while(true) if(dinic(1)) --ans; else break; } if(!ans){ putchar('1'); for(int i=1;i<=n;++i){ putchar(10); for(int j=head[i+1];j;j=nxt[j]) if(!wei[j]) printf("%d ",to[j]-n-1); } } else putchar('0'); return 0; } int read(){ int in = 0; char ch = getchar(); while(ch>'9'||ch<'0') ch = getchar(); while(ch<='9'&&ch>='0'){ in = in*10+ch-'0'; ch = getchar(); } return in; } void add(int from,int tp,int value){ ++tot;nxt[tot]=head[from];head[from]=tot;to[tot]=tp;wei[tot]=value; ++tot;nxt[tot]=head[tp];head[tp]=tot;to[tot]=from;wei[tot]=0; } bool bfs(){ int now,H=0,T=1; memset(c,0,sizeof c); c[1] = 1; que[1] = 1; do{ now = que[++H]; for(int i=head[now];i;i=nxt[i]) if(!c[to[i]] && wei[i]){ c[to[i]] = c[now]+1; que[++T] = to[i]; } }while(H<T); return c[n+m+2]; } bool dinic(int place){ if(place == n+m+2) return true; for(int &i=cur[place];i;i=nxt[i]) if(c[to[i]]==c[place]+1 && wei[i]) if(dinic(to[i])){ --wei[i]; ++wei[i^1]; return true; } return false; }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性