1. 程式人生 > >網路流24題 P3254 圓桌問題 (二分圖多重匹配轉最大流)

網路流24題 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<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
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)
{
	queue<int>q;
	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;
}