题解

又写了一遍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. 洛谷P4382 [八省联考2018]劈配(网络流,二分答案)

    洛谷题目传送门 说不定比官方sol里的某理论最优算法还优秀一点? 所以\(n,m\)说不定可以出到\(1000\)? 无所谓啦,反正是个得分题.Orz良心出题人,暴力有70分2333 思路分析 正解的 ...

  2. JS发送跨域Post请求出现两次请求的解决办法

    原文地址: http://www.cnblogs.com/JimmyBright/p/7681097.html 所有跨域的js在提交post请求的时候,如果服务端设置了可跨域访问 public sta ...

  3. 【BZOJ 3451】Tyvj1953 Normal 思维题+期望概率+FFT+点分治

    我感觉是很强的一道题……即使我在刷专题,即使我知道这题是fft+点分治,我仍然做不出来……可能是知道是fft+点分治限制了我的思路???(别做梦了,再怎样也想不出来的……)我做这道题的话,一看就想单独 ...

  4. WebService注解总结

    @WebService 1.serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service.缺省值为 Java 类的简单名称 + Service.(字符 ...

  5. string::replace

    #include <string> #include <cctype> #include <algorithm> #include <iostream> ...

  6. java基础知识代码-------枚举类型

    package com.mon10.day22; /** * 类说明 :枚举类型,案例二 * * @author 作者 : chenyanlong * @version 创建时间:2017年10月22 ...

  7. python Flask post 数据 输出

    #!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flask from flask import request from ...

  8. Codeforces 923 B. Producing Snow

    http://codeforces.com/contest/923/problem/B 题意: 有n天,每天产生一堆体积为Vi的雪,每天所有雪堆体积减少Ti 当某一堆剩余体积vi<=Ti时,体积 ...

  9. HDU 3389 阶梯博弈变形

    n堆石子,每次选取两堆a!=b,(a+b)%2=1 && a!=b && 3|a+b,不能操作者输 选石子堆为奇数的等价于选取步数为奇数的,观察发现 1 3 4 是无法 ...

  10. Docker 入门 第一部分: 定位和设置

    目录 Docker 入门 第一部分: 定位和设置 Docker概念 镜像和容器 容器和虚拟机 准备你的Docker环境 测试 Docker 的版本 测试 Docker 安装 回顾 总结 Docker ...