您的位置:首页 > 理论基础 > 计算机网络

圆桌问题[网络流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 5

4 5 3 5

3 5 2 6 4

输出文件示例:

1

1 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++