【LOJ】 #6012. 「网络流 24 题」分配问题
题解
又写了一遍KM算法,这题刚好是把最大最小KM拼在一起写的,感觉比较有记录价值
感觉KM始终不熟啊QAQ
算法流程大抵如下,原理就是每次我们通过减少最少的匹配量达成最大匹配,所以获得的一定是最大价值
1.我们先给左部点求一个期望大小,如果是最大KM,期望大小就是最大的那条边的权值,如果是最小KM,期望大小就是最小的那条边的权值
2.然后跑二分图匹配,两个点能匹配的条件是左点\(u\)的期望值加右点\(v\)的期望值刚好是边权
3.给无法访问的点更新断层大小,如果是最小匹配,那么断层就是\(c[u][v] - (ex_l[u] + ex_r[v])\),如果是最大匹配,就是\((ex_l[u] + ex_r[v]) - c[u][v]\)
4.在没有被访问的右点里寻找最小的减少量\(d\)
5.给访问过的左点和右点,如果是最小匹配,左点加上\(d\),因为要包括进一些更大的边,右点减去\(d\),如果是最大匹配,左点减去\(d\),因为要包括进一些更小的边,右点加上\(d\)
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int, int>
#define pdi pair<db, int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 205
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template <class T>
void read(T &res) {
res = 0;
char c = getchar();
T f = 1;
while (c < '0' || c > '9') {
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template <class T>
void out(T x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N;
int c[105][105];
int ex_l[105], ex_r[105], slack[105], matc[105];
bool vis_l[105], vis_r[105];
bool match(int u, int on) {
vis_l[u] = 1;
for (int v = 1; v <= N; ++v) {
if (!vis_r[v]) {
if (vis_r[v])
continue;
int gap;
if (on == 0)
gap = c[u][v] - ex_l[u] - ex_r[v];
else
gap = ex_l[u] + ex_r[v] - c[u][v];
if (gap == 0) {
vis_r[v] = 1;
if (!matc[v] || match(matc[v], on)) {
matc[v] = u;
return true;
}
} else
slack[v] = min(slack[v], gap);
}
}
return false;
}
int KM(int on) {
for (int i = 1; i <= N; ++i) {
ex_r[i] = 0;
if (on == 0)
ex_l[i] = 0x7fffffff;
else
ex_l[i] = 0;
for (int j = 1; j <= N; ++j) {
if (on == 0)
ex_l[i] = min(ex_l[i], c[i][j]);
else
ex_l[i] = max(ex_l[i], c[i][j]);
}
}
memset(matc, 0, sizeof(matc));
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= N; ++j) slack[j] = 0x7fffffff;
while (1) {
memset(vis_l, 0, sizeof(vis_l));
memset(vis_r, 0, sizeof(vis_r));
if (match(i, on))
break;
int d = 0x7fffffff;
for (int j = 1; j <= N; ++j) {
if (!vis_r[j])
d = min(d, slack[j]);
}
for (int j = 1; j <= N; ++j) {
if (on == 0) {
if (vis_l[j])
ex_l[j] += d;
if (vis_r[j])
ex_r[j] -= d;
else
slack[j] -= d;
} else {
if (vis_l[j])
ex_l[j] -= d;
if (vis_r[j])
ex_r[j] += d;
else
slack[j] -= d;
}
}
}
}
int res = 0;
for (int v = 1; v <= N; ++v) {
res += c[matc[v]][v];
}
return res;
}
void Solve() {
read(N);
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= N; ++j) {
read(c[i][j]);
}
}
out(KM(0));
enter;
out(KM(1));
enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in", "r", stdin);
#endif
Solve();
return 0;
}
【LOJ】 #6012. 「网络流 24 题」分配问题的更多相关文章
- 【刷题】LOJ 6012 「网络流 24 题」分配问题
题目描述 有 \(n\) 件工作要分配给 \(n\) 个人做.第 \(i\) 个人做第 \(j\) 件工作产生的效益为 \(c_{ij}\) .试设计一个将 \(n\) 件工作分配给 \(n\) ...
- 2018.10.14 loj#6012. 「网络流 24 题」分配问题(费用流)
传送门 费用流水题. 依然是照着题意模拟建边就行了. 为了练板子又重新写了一遍费用流. 代码: #include<bits/stdc++.h> #define N 305 #define ...
- Libre 6012 「网络流 24 题」分配问题 (网络流,费用流)
Libre 6012 「网络流 24 题」分配问题 (网络流,费用流) Description 有n件工作要分配给n个人做.第i个人做第j件工作产生的效益为\(c_{ij}\).试设计一个将n件工作分 ...
- 【刷题】LOJ 6227 「网络流 24 题」最长k可重线段集问题
题目描述 给定平面 \(\text{xoy}\) 上 \(n\) 个开线段组成的集合 \(\text{I}\) ,和一个正整数 \(k\) ,试设计一个算法. 从开线段集合 \(\text{I}\) ...
- [luogu_P1251][LOJ#6008]「网络流 24 题」餐巾计划
[luogu_P1251][LOJ#6008]「网络流 24 题」餐巾计划 试题描述 一个餐厅在相继的 \(N\) 天里,第 \(i\) 天需要 \(R_i\) 块餐巾 \((i=l,2,-,N)\) ...
- [LOJ#6002]「网络流 24 题」最小路径覆盖
[LOJ#6002]「网络流 24 题」最小路径覆盖 试题描述 给定有向图 G=(V,E).设 P 是 G 的一个简单路(顶点不相交)的集合.如果 V 中每个顶点恰好在 P 的一条路上,则称 P 是 ...
- loj #6014. 「网络流 24 题」最长 k 可重区间集
#6014. 「网络流 24 题」最长 k 可重区间集 题目描述 给定实直线 L LL 上 n nn 个开区间组成的集合 I II,和一个正整数 k kk,试设计一个算法,从开区间集合 I II 中选 ...
- loj #6013. 「网络流 24 题」负载平衡
#6013. 「网络流 24 题」负载平衡 题目描述 G 公司有 n nn 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 n nn 个仓库的库存数量相同.搬运货物时 ...
- loj #6122. 「网络流 24 题」航空路线问题
#6122. 「网络流 24 题」航空路线问题 题目描述 给定一张航空图,图中顶点代表城市,边代表两个城市间的直通航线.现要求找出一条满足下述限制条件的且途经城市最多的旅行路线. 从最西端城市出发,单 ...
随机推荐
- Merkle Tree 概念
Merkle Tree 概念 来源 https://www.cnblogs.com/fengzhiwu/p/5524324.html /*最近在看Ethereum,其中一个重要的概念是Merkle T ...
- 字符编码问题mysql
2019-02-27 07:32:17.108 ERROR 21745 --- [nio-8086-exec-2] c.h.h.rest.configurer.WebMvcConfigurer : 接 ...
- 结合NTLM中继和Kerberos委派攻击AD
0x00 前言 在上个月我深入演讲了无约束委派之后,本文将讨论一种不同类型的Kerberos委派:基于资源的约束委派.本文的内容基于Elad Shamir的Kerberos研究,并结合我自己的NTLM ...
- LookupError: unknown encoding: cp65001解决方案
本人遇到这个问题搜索了很多网站,有人建议在cmd中执行命令chcp 936,然而,,,最终决定更换cmd窗口,window的cmd真的很烂, 果断使用git cmd,完美解决...
- Gulp 笔记
Gulp是一款自动化构建工具 用npm安装 npm install -g gulp npm install --save-dev gulp 分别在全局和项目目录里安装. 然后在项目目录里创建gulpf ...
- Java基础-Java中的内存分配与回收机制
Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二.
- Redis记录-JAVA连接Redis
在Java程序中使用Redis之前,需要确保在机器上安装了Redis的Java驱动程序和Java环境.可以先在将Java电脑上并配置好环境. 安装 现在,让我们看看如何设置Redis Java驱动程序 ...
- bzoj千题计划205:bzoj3529: [Sdoi2014]数表
http://www.lydsy.com/JudgeOnline/problem.php?id=3529 有一张n*m的数表,其第i行第j列(1 < =i < =n,1 < =j & ...
- bzoj千题计划183:bzoj1197: [HNOI2006]花仙子的魔法
http://www.lydsy.com/JudgeOnline/problem.php?id=1197 题意转化:在n维空间中放m个n维球,问最多将空间分成几部分 f[i][j] 表示在i维空间中放 ...
- 阿里云(一)云存储OSS的命令行osscmd的安装和使用
一.安装Python 在Linux Shell里验证Python版本: $ python -V Python 2.7.10 二.安装OSScmd SDK osscmd是基于python 2.5.4(其 ...