题目链接: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<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;
}
声明一下:虽然代码里有O2优化,但是提交的时候一律没有选择