题解

又写了一遍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 题」分配问题的更多相关文章

  1. 【刷题】LOJ 6012 「网络流 24 题」分配问题

    题目描述 有 \(n\) 件工作要分配给 \(n\) 个人做.第 \(i\) 个人做第 \(j\) 件工作产生的效益为 \(c_{ij}\) ​​.试设计一个将 \(n\) 件工作分配给 \(n\) ...

  2. 2018.10.14 loj#6012. 「网络流 24 题」分配问题(费用流)

    传送门 费用流水题. 依然是照着题意模拟建边就行了. 为了练板子又重新写了一遍费用流. 代码: #include<bits/stdc++.h> #define N 305 #define ...

  3. Libre 6012 「网络流 24 题」分配问题 (网络流,费用流)

    Libre 6012 「网络流 24 题」分配问题 (网络流,费用流) Description 有n件工作要分配给n个人做.第i个人做第j件工作产生的效益为\(c_{ij}\).试设计一个将n件工作分 ...

  4. 【刷题】LOJ 6227 「网络流 24 题」最长k可重线段集问题

    题目描述 给定平面 \(\text{xoy}\) 上 \(n\) 个开线段组成的集合 \(\text{I}\) ,和一个正整数 \(k\) ,试设计一个算法. 从开线段集合 \(\text{I}\) ...

  5. [luogu_P1251][LOJ#6008]「网络流 24 题」餐巾计划

    [luogu_P1251][LOJ#6008]「网络流 24 题」餐巾计划 试题描述 一个餐厅在相继的 \(N\) 天里,第 \(i\) 天需要 \(R_i\) 块餐巾 \((i=l,2,-,N)\) ...

  6. [LOJ#6002]「网络流 24 题」最小路径覆盖

    [LOJ#6002]「网络流 24 题」最小路径覆盖 试题描述 给定有向图 G=(V,E).设 P 是 G 的一个简单路(顶点不相交)的集合.如果 V 中每个顶点恰好在 P 的一条路上,则称 P 是  ...

  7. loj #6014. 「网络流 24 题」最长 k 可重区间集

    #6014. 「网络流 24 题」最长 k 可重区间集 题目描述 给定实直线 L LL 上 n nn 个开区间组成的集合 I II,和一个正整数 k kk,试设计一个算法,从开区间集合 I II 中选 ...

  8. loj #6013. 「网络流 24 题」负载平衡

    #6013. 「网络流 24 题」负载平衡 题目描述 G 公司有 n nn 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 n nn 个仓库的库存数量相同.搬运货物时 ...

  9. loj #6122. 「网络流 24 题」航空路线问题

    #6122. 「网络流 24 题」航空路线问题 题目描述 给定一张航空图,图中顶点代表城市,边代表两个城市间的直通航线.现要求找出一条满足下述限制条件的且途经城市最多的旅行路线. 从最西端城市出发,单 ...

随机推荐

  1. poj3667 Hotel (线段树 区间合并)

    poj3667 HotelTime Limit: 3000MS Memory Limit: 65536KTotal Submissions: 18925 Accepted: 8242Descripti ...

  2. 【USACO 1.4】Combination Lock

    /* TASK:combo LANG:C++ URL:http://train.usaco.org/usacoprob2?a=E6RZnAhV9zn&S=combo SOLVE:自己做,想的是 ...

  3. 循环取月的三位英语名 Jan Feb

    CultureInfo ci = new CultureInfo("en-US"); DateTime now = DateTime.Now; for (int i = 0; i ...

  4. 洛谷 P1070 道路游戏 解题报告

    P1070 道路游戏 题目描述 小新正在玩一个简单的电脑游戏. 游戏中有一条环形马路,马路上有\(n\)个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针顺序依 ...

  5. 【bzoj2440】 中山市选2011—完全平方数

    http://www.lydsy.com/JudgeOnline/problem.php?id=2440 (题目链接) 题意 求第K个不含有完全平方因子的数 Solution 没想到莫比乌斯还可以用来 ...

  6. 获取C++类成员虚函数地址

    1.GCC平台 GCC平台获取C++成员虚函数地址可使用如下方法[1]: class Base{ int i; public: virtual void f1(){ cout<<" ...

  7. [SCOI2014]方伯伯的商场之旅

    Description 方伯伯有一天去参加一个商场举办的游戏.商场派了一些工作人员排成一行.每个人面前有几堆石子.说来也巧,位置在 i 的人面前的第 j 堆的石子的数量,刚好是 i 写成 K 进制后的 ...

  8. 【疑点】js中的break,continue和return到底怎么用?

    转: [疑点]js中的break,continue和return到底怎么用? 为什么要说个?好像很简单,但是我也会迷糊,不懂有时候为什么要用return,然而break和continue也经常和他放在 ...

  9. django模板中的自定义过滤器

    (1)在APP下创建templatetags文件夹,与Models.py.views.py等同级,templatetags文件夹下添加__init__.py文件,可为空,再添加一个模块文件,例如cpt ...

  10. sqoop的安装与配置

    最近需要将MySQL的数据导出到HDFS,所以搜到了sqoop2.跟sqoop1相比,sqoop2的好处是直接使用程序连接到集群上的sqoop,远程操作.流程是需要先创建link也可以理解成要操作的对 ...