0
点赞
收藏
分享

微信扫一扫

hdu3488 Tour km求完备匹配最小值 带图解析

爪哇驿站 2022-06-29 阅读 22

​​传送门​​​ 题意:给你一些 从某一景点到某一景点 的距离,让你求能否遍历全部景点,并且至少走一个环。
思路:我们发现,只要遍历全部的景点一次,且又回到了起点,那么一定会有一个完备匹配,我们可以将一个景点拆成两个点,比如u -> u和u’。将这两个点一个放在x部,一个放在y部。然后按照题意连接,如果图中存在一个环的话,那么下图x集和y集一定存在完备匹配。比如:
路径:1-4-5-3-2-1
hdu3488 Tour km求完备匹配最小值 带图解析_sed理解了这些概念之后,我们发现可以用Km算法来求解,即将求最大值的方法用来求最小值即可。
1.将所有点和点的距离初始化为-无穷,然后对个点到点的距离取反,这样我们在求最大值的时候,是在负数中求的,那么最后我们只要对结果取反即可。

w[a][b] = max(w[a][b], -c);
这是一个大坑,可能会有重复的点,那么我们要留下最大的点。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<cmath>
#include<cctype>
#include<stack>
#include<map>
#include<string>
#include<cstdlib>
#define min(a,b) a>b?b:a
#define max(a,b) a>b?a:b
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 400, INF = 0x3f3f3f3f;
int usedx[maxn], usedy[maxn], w[maxn][maxn], bx[maxn], by[maxn], cx[maxn], cy[maxn];
long long nx, ny, n, minn, max_value, m;
int dfs(int u) {
usedx[u] = 1;
for(int i = 1; i <= ny; i++) {
if(usedy[i] == -1) {
int t = bx[u] + by[i] - w[u][i];
if(t == 0) {
usedy[i] = 1;
if(cy[i] == -1 || dfs(cy[i])) {
cy[i] = u;
cx[u] = i;
return 1;
}
} else if(t > 0)
minn = min(minn, t);
}
}
return 0;
}
int km() {
mem(cx, -1);
mem(cy, -1);
mem(bx, -1);
mem(by, 0);
for(int i = 1; i <= nx; i++)
for(int j = 1; j <= ny; j++)
bx[i] = max(bx[i], w[i][j]);
for(int i = 1; i <= nx; i++) {
while(1) {
minn = INF;
mem(usedx, -1);
mem(usedy, -1);
if(dfs(i)) break;
for(int j = 1; j <= nx; j++)
if(usedx[j] != -1) bx[j] -= minn;
for(int j = 1; j <= ny; j++)
if(usedy[j] != -1) by[j] += minn;
}
}
max_value = 0;
for(int i = 1; i <= nx; i++)
if(cx[i] != -1)
max_value += w[i][cx[i]];
cout << -max_value << endl;
return 1;
}

int main() {
int T;
cin >> T;
while(T--) {
mem(w, -INF);
cin >> n >> m;
for(int i = 1; i <= m; i++) {
int a, b, c;
cin >> a >> b >> c;
w[a][b] = max(w[a][b], -c);
}
nx = ny = n;
km();
}
return 0;
}


举报

相关推荐

0 条评论