网络流24题 圆桌问题(二分图多重匹配转最大流)

题目链接:https://www.luogu.org/problemnew/show/P3254

假设有来自m 个不同单位的代表参加一次国际会议。每个单位的代表数分别为ri (i =1,2,……,m)。

会议餐厅共有n 张餐桌,每张餐桌可容纳ci (i =1,2,……,n)个代表就餐。

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

对于给定的代表数和餐桌数以及餐桌容量,编程计算满足要求的代表就餐方案。

输入输出格式

输入格式:

 

第1 行有2 个正整数m 和n,m 表示单位数,n 表示餐桌数,1<=m<=150, 1<=n<=270。

第2 行有m 个正整数,分别表示每个单位的代表数。

第3 行有n 个正整数,分别表示每个餐桌的容量。

 

输出格式:

 

如果问题有解,第1 行输出1,否则输出0。接下来的m 行给出每个单位代表的就餐桌号。如果有多个满足要求的方案,只要输出1 个方案。

 

输入输出样例

输入样例#1: 复制

4 5
4 5 3 5
3 5 2 6 4

输出样例#1: 复制

1
1 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5

源点向单位Xi连容量为该单位人数的线,Yi向汇点连餐桌容量的线。
每个Xi向每个Yi连容量为1的线
求最大流,若最大流等于单位人数之和,则有解

建图思想比较难,建出图还是比较简单的一个题了

#pragma GCC optimize(2)
#include
#include
#include
#include
using namespace std;
const int maxn = 1e5;
const int inf = 0x3f3f3f3f;
typedef long long ll;
int head[maxn], level[maxn], r[maxn], c[maxn];
int n, m, tot;
struct node
{
	int v, w, next;
}edge[maxn];
void addedge(int u, int v, int w)
{
	edge[tot].v = v;
	edge[tot].w = w;
	edge[tot].next = head[u];
	head[u] = tot++;

	edge[tot].v = u;
	edge[tot].w = 0;
	edge[tot].next = head[v];
	head[v] = tot++;
	return;
}
bool bfs(int s, int t)
{
	queueq;
	memset(level, 0, sizeof(level));
	level[s] = 1;
	q.push(s);
	while (!q.empty())
	{
		int u = q.front();
		q.pop();
		for (int i = head[u]; i != -1; i = edge[i].next)
		{
			int v = edge[i].v;
			if (level[v] == 0 && edge[i].w)
			{
				level[v] = level[u] + 1;
				q.push(v);
			}
		}
	}
	return level[t] != 0;
}
int dfs(int s, int t, int f)
{
	if (s == t)
	{
		return f;
	}
	int cost = 0;
	for (int i = head[s]; i != -1; i = edge[i].next)
	{
		int v = edge[i].v;
		int w = edge[i].w;
		if (level[v] == level[s] + 1 && w)
		{
			int d = dfs(v, t, min((f - cost), w));
			if (d > 0)
			{
				edge[i].w -= d;
				edge[i^1].w += d;
				cost += d;
				if (cost == f)
				{
					break;
				}
			}
			else
			{
				level[v] = 0;
			}
		}
	}
	return cost;
}
int dinic(int s, int t)
{
	int flow = 0;
	while (bfs(s, t))
	{
		flow += dfs(s, t, inf);
	}
	return flow;
}
int main()
{
	//freopen("C://input.txt", "r", stdin);
	scanf("%d%d", &m, &n);
	memset(head, -1, sizeof(head));
	int sum = 0;
	int s = 0, t = m + n + 1;
	for (int i = 1; i <= m; i++)
	{
		scanf("%d", &r[i]);
		addedge(s, i, r[i]);
		sum += r[i];
	}
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &c[i]);
		addedge(i + m, t, c[i]);
	}
	for (int i = 1; i <= m; i++)
	{
		for (int j = m + 1; j <= n + m; j++)
		{
			addedge(i, j, 1);
		}
	}
	if (sum == dinic(s, t))
	{
		printf("1\n");
		for (int i = 1; i <= m; i++)
		{
			for (int j = head[i]; j != -1; j = edge[j].next)
			{
				if (edge[j ^ 1].w)
				{
					printf("%d ", edge[j].v - m);
				}
			}
			printf("\n");
		}
	}
	else
	{
		printf("0\n");
	}
	return 0;
}

声明一下:虽然代码里有O2优化,但是提交的时候一律没有选择

你可能感兴趣的:(网络流)