oi不需要证明,确实因为时间有限,还有脑力有限,咳咳~就直接给结论和算法流程了
二分图有两类点,这里称类,和类。
-
顶标:和,分别表示类点和类点的顶标。此算法全程任意边满足。
-
相等子图:由满足的边构成的子图。
-
性质:相同子图存在原图的完美匹配,则一定是最大完美匹配。
-
目标:满足 的情况下调整顶标,加入边到相等子图中找增广路,使得得到原图的完美匹配。
-
算法流程:我们在匈牙利算法找增广路的背景下设计该算法。
1.从中每个点出发,找增广路。
2.找到增广路则结束
3.否则,通过改顶标加入一边。回到。
流程很简单,不过怎么改顶标。
首先明确要找的边从已经遍历到的点连向还未遍历到的点。
因此可以将遍历到的边 ,,这样遍历到的边不会改变但满足上面的边会减少。
综上加入此类边中最小的边即可。
而查询最小可以用slack优化至,维护中未遍历到的每个点到所有中遍历到的点的
每次加边导致中有新点被遍历,直接更新,查询扫一遍找新边也是的。
流程结合代码看一下就好了,注意改顶标时别漏了起点(从开始遍历)。
由于每次是加入一条边,所以直接用bfs迭代的思想即可(写的也不像bfs)。
看代码显然: -
code
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf = 1e18;
const int N = 505;
int pre[N], link[N], n;
ll ex[N], ey[N], mp[N][N], slack[N];
bool visy[N];
void KM() {
for(int s = 1; s <= n; s++) {
for(int i = 1; i <= n; i++) {slack[i] = inf; pre[i] = 0; visy[i] = 0;}
int x, y = 0; link[y] = s;
while(1) {
x = link[y]; visy[y] = 1;
ll dta = inf, ny;
for(int i = 1; i <= n; i++) {
if(visy[i]) continue;
ll w = ex[x] + ey[i] - mp[x][i];
if(slack[i] > w) {slack[i] = w; pre[i] = y;}
if(dta > slack[i]) {dta = slack[i]; ny = i;}
}
for(int i = 0; i <= n; i++) { //link0=s
if(visy[i]) {ex[link[i]] -= dta; ey[i] += dta;}
else {slack[i] -= dta;}
}
y = ny;
if(!link[y]) {break;}
}
while(y) {link[y] = link[pre[y]]; y = pre[y];}
}
ll res = 0;
for(int i = 1; i <= n; i++) res += mp[link[i]][i];
printf("%lld\n", res);
for(int i = 1; i <= n; i++) {printf("%d ", link[i]);}
}
int main() {
int m; scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {for(int j = 1; j <= n; j++) mp[i][j] = -inf; ex[i] = -inf;}
for(int i = 1; i <= m; i++) {
int u, v; ll w; scanf("%d%d%lld", &u, &v, &w);
mp[u][v] = max(mp[u][v], w);
ex[u] = max(ex[u], w);
}
KM();
return 0;
}
- 非完美匹配
- 首先保证
- 一定要是完美匹配,首先,虚边设,中每个点出发如果到的为,也就是无边那就无解。
- 最大匹配就行:虚边都是。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人