网络流24题-5
来源:互联网 发布:ubuntu删除文件夹命令 编辑:程序博客网 时间:2024/06/07 11:53
圆桌问题
«问题描述:
假设有来自 n 个不同单位的代表参加一次国际会议。每个单位的代表数分别为
r i , i = 1 , 2 , , n 。会议餐厅共有 m 张餐桌,每张餐桌可容纳 c i ( i = 1 , 2 , , m ) 个代表就餐。
为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。
试设计一个算法,
给出满足要求的代表就餐方案。
«编程任务:
对于给定的代表数和餐桌数以及餐桌容量,编程计算满足要求的代表就餐方案。
«数据输入:
由文件 input.txt 提供输入数据。文件第 1 行有 2 个正整数 m 和 n,m 表示单位数,n 表
示餐桌数,1<=m<=150, 1<=n<=270。文件第 2 行有 m 个正整数,分别表示每个单位的代表
数。文件第 3 行有 n 个正整数,分别表示每个餐桌的容量。
«结果输出:
程序运行结束时,将代表就餐方案输出到文件 output.txt 中。如果问题有解,在文件第
1 行输出 1,否则输出 0。接下来的 m 行给出每个单位代表的就餐桌号。如果有多个满足要
求的方案,只要输出 1 个方案。
输入文件示例
input.txt
4 5
4 5 3 5
3 5 2 6 4
输出文件示例
output.txt
1
1 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5
【问题分析】
二分图多重匹配问题,可以用最大流解决。
【建模方法】
建立二分图,每个单位为X集合中的顶点,每个餐桌为Y集合中的顶点,增设附加源S和汇T。
1、从S向每个Xi顶点连接一条容量为该单位人数的有向边。
2、从每个Yi顶点向T连接一条容量为该餐桌容量的有向边。
3、X集合中每个顶点向Y集合中每个顶点连接一条容量为1的有向边。
求网络最大流,如果最大流量等于所有单位人数之和,则存在解,否则无解。对于每个单位,从X集合对应点出发的所有满流边指向的Y集合的顶点就是该单位人员的安排情况(一个可行解)。
【建模分析】
对于一个二分图,每个顶点可以有多个匹配顶点,称这类问题为二分图多重匹配问题。X,Y集合之间的边容量全部是1,保证两个点只能匹配一次(一个餐桌上只能有一个单位的一个人),源汇的连边限制了每个点匹配的个数。求出网络最大流,如果流量等于X集合所有点与S边容量之和,那么则说明X集合每个点都有完备的多重匹配。
【问题另解】
贪心,更好的方法其实是贪心。首先把所有单位和餐桌按人数从大到小排序,一种适当的贪心策略就是对于每个单位,所有人每次尽量去剩余容量较大的餐桌就坐。按照这种贪心策略,如果某时发现有人已经无法就坐,则无解。具体方法为用线段树维护餐桌的剩余容量,按人数从多到少安排每个单位的人员,每次安排就是把容量餐桌前k大的餐桌人数减1(k为该单位人数)。为保证线段树前k位时刻为前k大,要维护第k与第k+1,k+2,…人数与第k相等的位置,减少第k大时要减少尽量靠后的,这样才能保证单调。
#include<iostream>#include<math.h>#include<cstring>#include<algorithm>#include<set>#include<map>#include<queue>#include<cstdio>#include<vector>const int INF=0x7fffffff;const int maxn=4001;using namespace std;struct edge{ int to,cap,rev;};vector<edge> G[maxn];int iter[maxn],match[maxn],path[maxn],level[maxn];bool book[maxn];int m,n,OFFSET=500,s,t,maxflow,ans;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});}void bfs(int s){ 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<G[v].size();i++) { edge &e=G[v][i]; if(e.cap&&level[e.to]<0) { level[e.to]=level[v]+1; que.push(e.to); } } }}int dfs(int v,int t,int f){ if(v==t) return f; for(int &i=iter[v];i<G[v].size();i++) { edge &e=G[v][i]; if(e.cap&&level[e.to]>level[v]) { int d=dfs(e.to,t,min(e.cap,f)); if(d>0) { e.cap-=d; G[e.to][e.rev].cap+=d; return d; } } } return 0;}int max_flow(int s,int t){ int flow=0; for(;;) { bfs(s); if(level[t]<0) return flow; memset(iter,0,sizeof(iter)); int f=0; while((f=dfs(s,t,INF))>0) flow+=f; }}void init(){ cin>>m>>n; s=0,t=n+m+1; int x; for(int i=1;i<=m;i++) { cin>>x; add_edge(s,i,x); ans+=x; } for(int i=m+1;i<=n+m;i++) { cin>>x; add_edge(i,t,x); } for(int i=1;i<=m;i++) for(int j=m+1;j<=m+n;j++) add_edge(i,j,1);}void solve(){ maxflow=max_flow(s,t);}void print(){ if(maxflow==ans) cout<<1<<endl; else { cout<<0<<endl; return ; } for(int i=1;i<=m;i++) { for(int j=0;j<G[i].size();j++) { edge e=G[i][j]; if(e.to!=s&&e.cap==0) cout<<e.to-m<<" "; } cout<<endl; }}int main(){ init(); solve(); print(); return 0;}
- 网络流24题-5
- 【网络流】网络流24题
- [网络流]: 网络流24题
- 网络流24题
- 网络流24题
- 网络流24题
- 网络流24题
- [网络流24题 #5]圆桌问题
- 网络流24题5 圆桌问题
- 网络流24题5 圆桌问题
- 网络流24题---餐巾纸
- [网络流24题] 餐巾
- 网络流24题-2
- 网络流24题-3
- 网络流24题-4
- 网络流24题-6
- 网络流24题-7
- 网络流24题-8
- SteamVR
- UE4学习笔记20th:扩展游戏模式
- 使用redis作为缓存,数据还需要存入数据库中吗?
- 数据结构 树 二叉树的建立及遍历 C语言版
- 复选框(JCheckBox)
- 网络流24题-5
- 分别用Java和Scala求PV,UV测试程序
- UVA 10706 Number Sequence(模拟)
- Redis + Spring 的集成示例
- Gabor滤波
- reduceByKey和groupByKey区别与用法
- 关于Android的Context的使用和注意,防止内存泄漏和异常
- python_lintcode_47主元素_47主元素 II_48主元素 III
- 数组模拟链表之学生排队