uoj#80 二分图最大权匹配
题意:给定二分图,有边权,求最大边权匹配。边权非负。
解:KM算法求解最大权完备匹配。
完备匹配就是点数少的那一边每个点都有匹配。
为了让完备匹配与最大权匹配等价,我们添加若干条0边使之成为完全二分图(自造名词别在意......)
为了让左边成为点数较少的一边,我们还要添加一些虚点,m = max(n,m)
然后求解完备匹配。
KM的DFS写法会被卡成n4,如果你不在意可以写......反正在uoj上会被卡爆。
模板就不放了,反正没啥用,放了还我 误 我 自 己。
过程就是一次为每个点寻找匹配。首先每个点都有个顶标(期望匹配值),最后要使得每一条匹配边(x, y)满足w[x] + w[y] = val(x, y)
然后每个右边的点还有个need数组,一般是叫做slack,就是松弛量,也就是当前这个点最少要把w减去多少才能匹配上。
还有个D是min slack,也就是全局最少减少D才能得到匹配。
匹配的时候跟匈牙利一样DFS,注意到一个点之后如果w[x] + w[y] = val(x, y)则这条边可用,打上vis,否则用差值更新need y
如果没有匹配就update一遍,每个有vis的左边减去D,右边加上D。然后继续直到有匹配为止。
BFS写法
这个我不太懂...话说DFS本来就不懂了,还纠结这个干啥。
右边节点有个pre数组表示它是谁更新来的,也就是如果它进入增广路,那么它前面的右边节点是pre
在BFS函数里首先设置BFS起点是右边0匹配左边x,然后尝试为x找到增广路。
枚举每个未被vis的y,得到w[x] + w[y]与val(x, y)的差值。
用这个差值更新need[y],如果差值比need[y]小,就表明y的前一个节点是mat[x]的话会更佳,令pre[y] = u(u表示正在匹配x的节点,也就是上一个x准备匹配的节点)
用need[y]更新D,如果need[y] < D则表明全局上下一个点选择y更优,令nex = y(此处nex是下一轮的u)
然后更新一遍,让所有vis的右边节点(当然也包括一开始我们虚拟跟x匹配的右边0号点)w += D,而与之匹配的左边节点w -= D
结束条件是找到的这个u没有匹配。此时增广路就找到了。
然后把交错路取反,也就是每个u的匹配变成上一个u的匹配,直到倒数第二个u匹配x。
啊我到底在口胡些什么
//thanks to yyb
#include <cstdio>
#include <algorithm>
#include <cstring> typedef long long LL;
const int N = ;
const LL INF = 0x3f3f3f3f3f3f3f3f; int vis[N * ], mat[N * ], Time, pre[N * ], n, m;
LL val[N][N], w[N * ], need[N * ]; void BFS(int x) {
memset(need, 0x3f, sizeof(need));
memset(pre, , sizeof(pre));
int u = , nex;
mat[u] = x;
do {
x = mat[u];
LL D = INF;
vis[u] = Time;
for(int y = n + ; y <= n + m; y++) {
if(vis[y] == Time) {
continue;
}
LL t = w[x] + w[y] - val[x][y - n];
if(t < need[y]) { // update need pre
need[y] = t;
pre[y] = u;
}
if(need[y] < D) { // update D nex
D = need[y];
nex = y;
}
}
// update
w[mat[]] -= D; // do not forget!
w[] += D;
for(int i = n + ; i <= n + m; i++) {
if(vis[i] == Time) {
w[mat[i]] -= D;
w[i] += D;
}
else {
need[i] -= D;
}
}
u = nex;
} while(mat[u]); while(u) { // update path
mat[u] = mat[pre[u]];
u = pre[u];
} return;
} int main() {
int q;
scanf("%d%d%d", &n, &m, &q);
m = std::max(n, m);
for(int i = ; i <= q; i++) {
int x, y;
LL z;
scanf("%d%d%lld", &x, &y, &z);
val[x][y] = std::max(val[x][y], z);
w[x] = std::max(w[x], val[x][y]);
}
for(int i = ; i <= n; i++) {
++Time; // ++Time
BFS(i);
}
LL ans = ;
for(int i = n + ; i <= n + m; i++) {
if(val[mat[i]][i - n]) { // do not forget " - n"!
mat[mat[i]] = i;
ans += val[mat[i]][i - n];
}
}
printf("%lld\n", ans);
for(int i = ; i <= n; i++) {
printf("%d ", mat[i] ? mat[i] - n : mat[i]);
}
return ;
}
AC代码
最后感谢YYB神犇,我是照抄他的代码的%%%%%%。
uoj#80 二分图最大权匹配的更多相关文章
- UOJ#80. 二分图最大权匹配 模板
#80. 二分图最大权匹配 描述 提交 自定义测试 从前一个和谐的班级,有 nlnl 个是男生,有 nrnr 个是女生.编号分别为 1,…,nl1,…,nl 和 1,…,nr1,…,nr. 有若干个这 ...
- UOJ#80 二分图最大权匹配 [模板题]
从前一个和谐的班级,有 nlnl 个是男生,有 nrnr 个是女生.编号分别为 1,…,nl1,…,nl 和 1,…,nr1,…,nr. 有若干个这样的条件:第 vv 个男生和第 uu 个女生愿意结为 ...
- @noi.ac - 507@ 二分图最大权匹配
目录 @description@ @solution@ @accepted code@ @details@ @description@ 有一天你学了一个能解决二分图最大权匹配的算法,你决定将这个算法应 ...
- [ACM] HDU 2255 奔小康赚大钱 (二分图最大权匹配,KM算法)
奔小康赚大钱 Problem Description 传说在遥远的地方有一个很富裕的村落,有一天,村长决定进行制度改革:又一次分配房子. 这但是一件大事,关系到人民的住房问题啊. 村里共同拥有n间房间 ...
- [hdu1533]二分图最大权匹配 || 最小费用最大流
题意:给一个n*m的地图,'m'表示人,'H'表示房子,求所有人都回到房子所走的距离之和的最小值(距离为曼哈顿距离). 思路:比较明显的二分图最大权匹配模型,将每个人向房子连一条边,边权为曼哈顿距离的 ...
- POJ2195 Going Home[费用流|二分图最大权匹配]
Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 22088 Accepted: 11155 Desc ...
- Hdu2255 奔小康赚大钱(二分图最大权匹配KM算法)
奔小康赚大钱 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好 ...
- POJ2195 Going Home (最小费最大流||二分图最大权匹配) 2017-02-12 12:14 131人阅读 评论(0) 收藏
Going Home Description On a grid map there are n little men and n houses. In each unit time, every l ...
- HDU2255 奔小康赚大钱 —— 二分图最大权匹配 KM算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) ...
随机推荐
- 剑指offer(7)
今天的几道题目都是关于斐波那契数列的. 题目1: 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0). n<=39 传统的方法采用递归函数,这种 ...
- Field tTypeMapper in com.atguigu.project.service.imp.projectInfoServiceImpl required a bean of type 'com.atguigu.project.mapper.TTypeMapper' that could not be found.
解决:MapperScan
- asyncio并发编程
一. 事件循环 1.注: 实现搭配:事件循环+回调(驱动生成器[协程])+epoll(IO多路复用),asyncio是Python用于解决异步编程的一整套解决方案: 基于asynico:tornado ...
- Javaweb小结之——JavaBean+持久层
数据持久层学习了JDBC.连接池以及DBUtil 思考一下,在学会使用SSM框架之前,还是先多使用DBUtil吧 数据库持久层的JDBC.连接池和DBUtil,这个链接给我了一些参考https://b ...
- sqlmap-学习1 配置环境
sqlmap是一款非常强大的开源sql自动化注入工具,可以用来检测和利用sql注入漏洞.它由python语言开发而成,因此运行需要安装python环境 1 安装 python (https://www ...
- Delphi MDI 子窗体的创建和销毁 [zhuan]
1.如果要创建一个mdi child,先看是否有这个child 存在,如果有,则用它,如果没有再创建 //该函数判断MDI 子窗体是否存在,再进行创建和显示function isInclude(for ...
- 二、两条Linux删除数据跑路命令
一.rm rm -rf / 无提示循环删除根目录,,删除存在被恢复的可能 二.dd dd if=/dev/urandom of=/dev/hda1 随机填写数据到相应分区,直到填满为止.重写后的分区无 ...
- Apache ab 单测 分布式
使用synchronized 处理并发 缺点:无法做到细粒度控制 只适合单点的情况 使用Redis作为分布式锁 setnx命令 设计模式 :使用 !setnx 加锁 getset命令
- Lodop“对象不支持SET__LICENSES属性或方法”SET__LICENSES is not a function”
Lodop中的方法如果书写错误,就会报错:“对象不支持XXX属性或方法”调试JS会报错”SET__LICENSES is not a function” LODOP.SET_LICENSES是加注册语 ...
- Zero to Build: Create new Xamarin apps in minutes with AppMap
Creating a new Xamarin.Forms app can be an intimidating task, especially if you add in content pages ...