题目链接

https://www.luogu.com.cn/problem/P6577

题目大意

给定一个二分图,其左右点的个数各为 \(n\),带权边数为 \(m\),保证存在完美匹配。

求一种完美匹配的方案,使得最终匹配边的边权之和最大。

题目解析

二分图最大权完美匹配,一般用 \(KM\) 算法完成。

基础版的 \(KM\) 算法,是匈牙利算法的改进,依然采用 \(DFS\) 策略,速度较慢。

而改进版的 \(KM\) 算法采用 \(BFS\) 策略,有效提升速度。

点数为 \(n\),边数为 \(m\) 。

时间复杂度: \(O(n^2 m)\)

参考代码

基础版(会超时)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 505;
int mp[N][N], lx[N], ly[N], visx[N], visy[N], match[N];
int n, m, minz, k; bool dfs(int x, int K)
{
visx[x] = K;
for (int y = 1; y <= n; ++y) {
if (visy[y] != K && mp[x][y] != INF) {
int t = lx[x] + ly[y] - mp[x][y];
if (!t) {
visy[y] = K;
if (!match[y] || dfs(match[y], K)) {
match[y] = x;
return true;
}
}
else minz = min(minz, t);
}
}
return false;
}
void KM()
{
for (int i = 1; i <= n; ++i) {
while (1) {
minz = INF;
if (dfs(i, ++k)) break;
for (int j = 1; j <= n; ++j) {
if (visx[j] == k) lx[j] -= minz;
if (visy[j] == k) ly[j] += minz;
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
memset(mp, INF, sizeof mp);
for (int i = 1; i <= n; ++i) lx[i] = -INF;
for (int i = 0; i < m; ++i) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
mp[u][v] = w;
lx[u] = max(lx[u], w);
}
KM();
ll ans = 0;
for (int i = 1; i <= n; ++i) ans += mp[match[i]][i];
printf("%lld\n", ans);
for (int i = 1; i <= n; ++i) printf("%d ", match[i]);
putchar('\n');
return 0;
}

改进版

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 505;
int mp[N][N], lx[N], ly[N], visy[N], matchy[N], pr[N], slack[N];
int n, m, minz, k; void bfs(int x, int K)
{
int y = 0, yy = 0;
memset(pr, 0, sizeof pr);
memset(slack, INF, sizeof slack);
matchy[y] = x;
while (true)
{
x = matchy[y];
visy[y] = K;
for (int i = 1; i <= n; ++i)
{
if (visy[i] == K || mp[x][i] == -INF) continue;
int t = lx[x] + ly[i] - mp[x][i];
if (slack[i] > t)
{
slack[i] = t;
pr[i] = y;
}
}
minz = INF;
for (int i = 1; i <= n; ++i) {
if (visy[i] != K && slack[i] < minz) {
minz = slack[i];
yy = i;
if (!minz) break;
}
}
if (minz) {
for(int i = 0; i <= n; ++i)
{
if (visy[i] == K) lx[matchy[i]] -= minz, ly[i] += minz;
else slack[i] -= minz;
}
}
y = yy;
if (!matchy[y]) break;
}
while (y) {
matchy[y] = matchy[pr[y]];
y = pr[y];
}
}
void KM()
{
for (int i = 1; i <= n; ++i) {
bfs(i, ++k);
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
mp[i][j] = -INF;
}
}
for (int i = 1; i <= n; ++i) lx[i] = -INF;
for (int i = 0; i < m; ++i) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
mp[u][v] = w;
lx[u] = max(lx[u], w);
}
KM();
ll ans = 0;
for (int i = 1; i <= n; ++i) ans += mp[matchy[i]][i];
printf("%lld\n", ans);
for (int i = 1; i <= n; ++i) printf("%d ", matchy[i]);
putchar('\n');
return 0;
}

感谢支持!

【模板】二分图最大权完美匹配(KM算法)/洛谷P6577的更多相关文章

  1. 【模板】二分图最大权完美匹配KM算法

    hdu2255模板题 KM是什么意思,详见百度百科. 总之知道它可以求二分图最大权完美匹配就可以了,时间复杂度为O(n^3). 给张图. 二分图有了边权,求最大匹配下的最大权值. 所以该怎么做呢?对啊 ...

  2. 二分图最大权完美匹配KM算法

    KM算法二分图 KM求得二分图与普通二分图的不同之处在于:此二分图的每条边(男生女生)上都附了权值(好感度).然后,求怎样完美匹配使得权值之和最大. 这,不止一般的麻烦啊. 可以通过一个期望值来求. ...

  3. 二分图最大权值匹配 KM算法 模板

    KM算法详解+模板 大佬讲的太好了!!!太好了!!! 转载自:http://www.cnblogs.com/wenruo/p/5264235.html KM算法用来求二分图最大权完美匹配. 本文配合该 ...

  4. HDU2255-奔小康赚大钱-二分图最大权值匹配-KM算法

    二分图最大权值匹配问题.用KM算法. 最小权值的时候把权值设置成相反数 /*-------------------------------------------------------------- ...

  5. 【二分图最大权完美匹配】【KM算法】【转】

    [文章详解出处]https://www.cnblogs.com/wenruo/p/5264235.html KM算法是用来求二分图最大权完美匹配的.[也就算之前的匈牙利算法求二分最大匹配的变种??] ...

  6. Solution -「洛谷 P6577」「模板」二分图最大权完美匹配

    \(\mathcal{Description}\)   Link.   给定二分图 \(G=(V=X\cup Y,E)\),\(|X|=|Y|=n\),边 \((u,v)\in E\) 有权 \(w( ...

  7. 二分图学习记 之 KM算法 二分图最大权完美匹配。

    前置知识 :匈牙利算法 首先有这样一张图,求这张图的最大权完美匹配. 当然如果你不想看这些渣图的话,您可以转到 洛谷 运动员最佳匹配问题 下面我来强行解释一下KM算法 左边一群妹子找汉子,但是每个妹子 ...

  8. uva 1411 Ants (权值和最小的完美匹配---KM算法)

    uva 1411 Ants Description Young naturalist Bill studies ants in school. His ants feed on plant-louse ...

  9. hdu 3722 二分图 最优完备匹配 KM算法

    这题只要想到是最优完备匹配就行了: 题意:给出n个字符串,若两两相连,将前一个反置添加到后一个后面,相连的值为两个字串从头开始相等的字符个数: 问如何匹配得出最大值: 思路:建图,套模板. 代码: # ...

随机推荐

  1. Spark面试题(二)

    首发于我的个人博客:Spark面试题(二) 1.Spark有哪两种算子? Transformation(转化)算子和Action(执行)算子. 2.Spark有哪些聚合类的算子,我们应该尽量避免什么类 ...

  2. 【BZOJ-2199】奶牛议会

    链接: BZOJ-2199 题意: 给出 \(n(1\leq n\leq 1000)\) 个点,\(m(1\leq m\leq 4000)\) 个形如:"点 \(a\) 取 \(ca\) 或 ...

  3. 基于屏幕空间的实时全局光照(Real-time Global Illumination Based On Screen Space)

    目录 Reflective Shadow Maps(RSM) RSM 的重要性采样 RSM 的应用与缺陷 Screen Space Ambient Occulsion(SSAO) SSAO Blur ...

  4. cf12E Start of the season(构造,,,)

    题意: 给一个偶数N. 构造出一个矩阵. 满足:主对角线上全为0.每一行是0~N-1的一个全排列.矩阵关于主对角线对称. 思路: 觉得是智商题,,,,看完题解后觉得不难,但是我就是没想出来.只想到了前 ...

  5. Device /dev/sdb excluded by a filter

    原因是添加的磁盘是在另一个虚拟机中新建的,已经有了分区表,现在的虚拟机并不能识别磁盘的分区表,运行parted命令重做分区表,中途需要输入三次命令(mklabel msdos -> yes-&g ...

  6. 『学了就忘』Linux基础命令 — 25、文件基本权限的管理

    目录 1.文件和目录的默认权限 2.umask默认权限 (1)查看系统的umask权限 (2)用八进制数值显示umask权限 (3)umask权限的计算方法 (4)注意:umask默认权限的计算绝不是 ...

  7. MySQL怎么缓解读的压力的?---buffer pool

    每当我们想要缓解读,一般会想到什么? 预读取,缓存 缓存 缓存,其实就是将高频访问的数据放到内存里面,减少读盘的次数. 为了提高内存的利用率,MySQL还建立了缓存池,也就是buffer pool,存 ...

  8. Emmet语法 —— 快速生成HTML结构

    快速生成HTML结构语法 1.生成单个标签 : 标签名+tab,比如 div 然后tab 键, 就可以生成 <div></div> 2.生成多个相同标签 div*3 + tab ...

  9. js 事件流和事件冒泡阻止

    js 事件流和事件冒泡阻止 事件流 当浏览器发展到第四代的时候(IE4与Netscape4)浏览器开发团队遇到一个有意思的的问题: 页面的哪一部分会拥有某个特定的事件? 比如在纸上画上一组同心圆,如果 ...

  10. 大一C语言学习笔记(7)---指针篇--什么是指针?什么是指针变量?取地址符“&”的作用是什么?地址运算符“*”的作用是什么,怎么理解两者?

    "指针是C语言的灵魂"这句话一开始我没怎么明白,现在接触了指针,终于知道为什么这么说了,因为....难,真难:下面说一下我对这句话的见解: C语言拥有着其他语言所没有的特性---直 ...