洛谷 P3254——圆桌问题【最大流 & Dinic算法 + 优化 & 另类贪心解法】

该博客讨论了洛谷P3254题目,即如何安排单位代表在不同餐桌就餐的问题,以避免同一单位的代表坐在同一餐桌。博主通过最大流算法和一种特殊的贪心策略解释了解题思路,并提供了AC代码。最大流算法用于建立单位与餐桌之间的二分图模型,而贪心策略则是按单位规模和餐桌容量排序来尝试分配。
摘要由CSDN通过智能技术生成

题目传送门


题目描述

假设有来自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 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值