题目描述
假设有来自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 个方案。
输入
4 5
4 5 3 5
3 5 2 6 4
输出
1
1 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5
题解
-
比较清爽的最大流(
奇水无比) -
这题建图感觉还是很显然的
-
首先可以看出一个明显的二分图模型, 单位是一种点, 餐桌是另一种点, 代表数量可以看做是流量.
-
从 s s s 连到所有单位点, 容量为代表数量. 单位点和餐桌点之间两两连一条容量为 1 1 1 的边代表"同一个单位来的代表不能在同一个餐桌就餐"的限制. 餐桌点再向 t t t 连一条容量为餐桌大小的边来限制这个餐桌的人数.
这样的话, 每一单位流量都代表着一个代表. 它们流经的点和边就代表了它们的特征. 而容量就是对代表的限制…
-
至于输出方案, 我们只要看从单位点到餐桌点的边有哪些满载了, 一条满载的边 ( u , v ) (u,v) (u,v) 意义就是在最优方案中一个来自 u u u 代表的单位的代表坐到了 v v v 代表的餐桌上.
当然如果最大流没有跑满 (最大流的值不等于代表数量之和) 的话肯定有代表没被分配出去, 判定无解.
有毒的贪心解法
瞎 ∗ ∗ ** ∗∗贪心的策略:
-
首先将桌子从大到小排个序,再讲单位的规模从大到小排个序。这样有什么用呢?因为单位规模越大就越难满足,所以我们优先考虑他们;
-
而对于桌子你可以这样想,你桌子数量越多显然更容易满足题意,又因为小桌子很容易坐爆而导致不能用,所以我们优先坐大桌子。
AC-Code
- Dinic解法:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int inf = 0x3f3f3f3f;
const int maxn = 150 * 270 + 150 + 270;
int n, m;
struct Edge {
int to;
int next;
int val;
}edge[maxn << 1]; // 双向边,开 2 倍数组
int head[maxn];
int cnt; // 边的数量,从 0 开始编号
int depth[maxn]; // 分层图标记深度
int cur[maxn]; // 当前弧优化,记录当前点 u 循环到了哪一条边
void add(int u, int v, int w) {
edge[cnt].to = v;
edge[cnt].next = head[u];
edge[cnt].val