(beginer) 网络流 UVA 10249 - The Grand Dinner

Problem D

The Grand Dinner

Input: standard input

Output: standard output

Time Limit: 15 seconds

Memory Limit: 32 MB

 

Each team participating in this year’s ACM World Finals contest is expected to join the grand dinner to be arranged after the prize giving ceremony ends. In order to maximize the interaction among the members of different teams, it is expected that no two members of the same team sit at the same table.

 

Now, given the number of members in each team (including contestants, coaches, reserves, guests etc.) and the seating capacity of each available table, you are to determine whether it is possible for the teams to sit as described in the previous paragraph. If such an arrangement is possible you must also output one possible seating arrangement. If there are multiple possible arrangements, any one is acceptable.

 

Input

 The input file may contain multiple test cases. The first line of each test case contains two integers M (1 ? M ? 70) and N (1 ? N ? 50) denoting the number of teams and the number of tables respectively. The second line of the test case contains M integers where the i-th (1 ? i ? M) integer mi (1 ? mi ? 100) indicates the number of members of team i. The third line contains N integers where the j-th (1 ? j ? N) integer nj (2 ? nj ? 100) indicates the seating capacity of table j.

 

A test case containing two zeros for M and N terminates the input.

 

Output

For each test case in the input print a line containing either 1 or 0 depending on whether or not there exists a valid seating arrangement of the team members. In case of a successful arrangement print M additional lines where the i-th (1 ? i ? M) of these lines contains a table number (an integer from 1 to N) for each of the members of team i.

 

Sample Input

4 5

4 5 3 5

3 5 2 6 4

4 5

4 5 3 5

3 5 2 6 3

0 0

 

 

Sample Output

1

1 2 4 5

1 2 3 4 5

2 4 5

1 2 3 4 5

0


(World Finals Warm-up Contest, Problem Setter: Rezaul Alam Chowdhury)

 

代码:有个M个队伍,N个桌子,你要为这些人安排位子,不能有两个同队的人做在一张桌子上。问怎么安排。

思路:我们可以用网络流来做,有一个源点连向每一个桌子,容量为桌子的容量,桌子连向每一个队伍,容量为1,每个队伍连向一个汇点,容量为队伍容量。套一下最大流的模板,如果最大流等于总人数,表示有可行的方案,看最终的残余网络,那些边有流残留,表示选择了这条路。。输出就行了。

代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 200;
const int inf = 1e9;
int n , m , sum;
bool ans[maxn][maxn];

struct Edge
{
Edge(int uu,int vv,int flow,int cap)
: u(uu) , v(vv) , flow(flow) , cap(cap) { }
int u , v;
int flow , cap;
};

vector<Edge> edge;
vector<int> G[maxn];

void add(int s,int t,int cap)
{
edge.push_back(Edge(s,t,0,cap));
edge.push_back(Edge(t,s,0,0));
int x = edge.size();
G[s].push_back(x-2);
G[t].push_back(x-1);
}

void input()
{
sum = 0;
for (int i = 0 ; i <= n+m+1 ; ++i) G[i].clear();
edge.clear();
for (int i = 1 ; i <= n ; ++i) {
int x;
scanf("%d",&x);
sum += x;
add(i,n+m+1,x);
}
for (int i = 1 ; i <= m ; ++i) {
int x; scanf("%d",&x);
add(0,n+i,x);
for (int j = 1 ; j <= n ; ++j) 
add(n+i,j,1);
}
}

struct ISAP 
{
int num[maxn] , d[maxn] , p[maxn] , cur[maxn];
int s , t , n;
void bfs() {
queue<int> q; q.push(t);
for (int i = 0 ; i < n ; ++i) d[i] = inf;
d[t] = 0;
while (q.size()) {
int u = q.front(); q.pop();
for (int i = 0 ; i < G[u].size() ; ++i) {
Edge & e = edge[G[u][i]];
if (e.cap == 0 && d[e.v]==inf) {
d[e.v] = d[u]+1;
q.push(e.v);
}
}
}
}

int Augment() {
int x = t , a = inf;
while (x!=s) {
Edge & e = edge[p[x]];
a = min(a,e.cap-e.flow);
x = e.u;
}
x = t;
while (x!=s) {
edge[p[x]].flow += a;
edge[p[x]^1].flow -= a;
x = edge[p[x]].u;
}
return a;
}

int maxflow(int s,int t,int n) {
this->s = s , this->t = t , this->n = n;
memset(cur,0,sizeof(cur));
memset(num,0,sizeof(num));
bfs();
int x = s , flow = 0;
for (int i = 0 ; i < n ; ++i) 
if (d[i]!=inf) ++num[d[i]];
while (d[s] < n) {
if (x==t) {
flow += Augment();
x = s;
}
bool ok = false;
for (int i = cur[x] ; i < G[x].size() ; ++i) {
Edge & e = edge[G[x][i]];
if (e.cap > e.flow && d[x]==d[e.v]+1) {
p[e.v] = G[x][i];
ok = true;
cur[x] = i;
x = e.v;
break;
}
}
if (!ok) {
int k = n-1;
for (int i = 0 ; i < G[x].size() ; ++i) {
Edge & e = edge[G[x][i]];
if (e.cap > e.flow) k = min(k,d[e.v]);
}
if (--num[d[x]]==0) break;
cur[x] = 0;
++num[d[x]=k+1];
if (x!=s) x = edge[p[x]].u;
}
}
return flow;
}
}solver;

int main()
{
while (scanf("%d%d",&n,&m)==2,n+m) {
input();
int ret = solver.maxflow(0,n+m+1,n+m+2);
if (ret!=sum) { printf("0\n"); continue; }
printf("1\n");
memset(ans,0,sizeof(ans));
for (int i = 1 ; i <= n ; ++i) {
for (int j = 0 ; j < G[i].size() ; ++j) {
Edge & e = edge[G[i][j]];
if (e.flow == -1) ans[i][e.v-n] = true;
}
}
for (int i = 1 ; i <= n ; ++i) {
bool first = true;
for (int j = 1 ; j <= m ; ++j) if (ans[i][j]) 
{
if (first) first = false;
else printf(" ");
printf("%d",j);
}
printf("\n");
}
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值