P3254 圆桌问题

题目描述

Link

有来自 \(m\) 个不同单位的代表参加一次国际会议。第 \(i\) 个单位派出了 \(r_i\) 个代表。

会议的餐厅共有 \(n\) 张餐桌,第 \(i\) 张餐桌可容纳 \(c_i\) 个代表就餐。

为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。请给出一个满足要求的方案.


第二道网络流24题 (应该算是比较简单的吧,毕竟自己这种蒟蒻都能想出来),芜湖起飞。

比较好想的二分图多重匹配问题。

我们从源点向每个单位连一条容量为 \(r_i\) 的边,表示这个单位需要在 \(r_i\) 张不同的桌子就餐。

在从餐桌向汇点连一条容量为 \(c_i\) 的边,表示这个餐桌最多能容纳 \(c_i\) 个人,也就是用来限制最大流的流量。

剩下的就把每个单位和每个餐桌之间连一条容量为 \(1\) 边,表示这个单位最多可以派一个人到那个餐桌就餐。

我们跑出来的最大流就是满足这样就餐的最多的人数。

无解的情况特判一下就可以。

输出方案的话就在残留网络中找边权为 \(0\) 的边输出就行。

Code

#include<iostream>
#include<cstdio>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int inf = 2147483647;
const int N = 1010;
int n,m,s,t,ans,sum,x,tot = 1;
int head[N],dep[N];
struct node
{
	int to,net,w;
}e[100010];
inline int read()
{
	int s = 0, w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
	return s * w;
}
void add(int x,int y,int w)
{
	e[++tot].w = w;
	e[tot].to = y;
	e[tot].net = head[x];
	head[x] = tot;
}
bool bfs()
{
	memset(dep,0,sizeof(dep));
	queue<int> q;
	q.push(s); dep[s] = 1;
	while(!q.empty())
	{
		int x = q.front(); q.pop();
		for(int i = head[x]; i; i = e[i].net)
		{
			int to = e[i].to;
			if(e[i].w && !dep[to])
			{
				q.push(to);
				dep[to] = dep[x] + 1;
				if(to == t) return 1;
			}
		}
	}
	return 0;
}
int dinic(int x,int flow)
{
	if(x == t) return flow;
	int rest = flow;
	for(int i = head[x]; i; i = e[i].net)
	{
		int to = e[i].to;
		if(e[i].w && dep[to] == dep[x] + 1)
		{
			int k = dinic(to,min(e[i].w,rest));
			if(!k) dep[to] = 0;
			e[i].w -= k;
			e[i^1].w += k;
			rest -= k;
		}
	}
	return flow - rest;
}
int main()
{
	n = read(); m = read();
	s = 0; t = n+m+1;
	for(int i = 1; i <= n; i++)
	{
		x = read(); sum += x;
		add(s,i,x); add(i,s,0);//源点向每个单位连一条边
	}
	for(int i = 1; i <= m; i++)
	{
		x = read();
		add(n+i,t,x); add(t,n+i,0);//每个桌子向汇点连边
	}
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= m; j++)
		{
			add(i,n+j,1); add(n+j,i,0);//单位和餐桌之间互相连边
		}
	}
	int flow = 0;
	while(bfs())
	{
		while(flow = dinic(s,inf)) ans += flow;
	}
	if(ans < sum)
	{
		printf("%d\n",0);
		return 0;
	}
	printf("%d\n",1);
	for(int i = 1; i <= n; i++)
	{
		for(int j = head[i]; j; j = e[j].net)
		{
			int to = e[j].to;
			if(e[j].w == 0) printf("%d ",to-n);
		}
		printf("\n");
	}
	return 0;
}
posted @ 2020-09-26 07:04  genshy  阅读(114)  评论(0编辑  收藏  举报