链接
http://codeforces.com/contest/875/problem/F
题意
给n个白点,m个黑点,其中第i个黑点和两个白点有边权为 wi 的边,求这个二分图的所有匹配中权值最大的匹配,输出最大的权值。
思路
贪心,之前自己写了一个按边贪心的,结果很容易就wa了 QAQ,看了题解发现要按点来贪心。
给黑点按权值从大到小排序,遍历每个黑点,一个黑点会和两个白点连边,不考虑这个黑点和哪个白点连边,而是把这两个白点缩成一个点,这样这个黑点就一定从两个白点中拿走了一个点,留下了一个点。如果拿到某个黑点只与一个缩点后的白点连边,那么这个黑点只能和这个白点连边,把这个白点标记为不能和其它黑点连边了就好。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5;
struct Node {
int u, v, w;
bool operator<(const Node &r) {
return w > r.w;
}
};
int n, m;
int pa[N];
bool full[N];
Node nodes[N];
int findset(int x) {
if (pa[x] == x) return x;
pa[x] = findset(pa[x]);
return pa[x];
}
int main() {
while (~scanf("%d%d", &n, &m)) {
for (int i = 0; i < m; ++i) scanf("%d%d%d", &nodes[i].u, &nodes[i].v, &nodes[i].w);
sort(nodes, nodes + m);
for (int i = 1; i <= n; ++i) pa[i] = i;
for (int i = 1; i <= n; ++i) full[i] = false;
int ans = 0, u, v;
for (int i = 0; i < m; ++i) {
u = findset(nodes[i].u);
v = findset(nodes[i].v);
if (u == v && !full[u]) {
ans += nodes[i].w;
full[u] = true;
}
else if (u != v && (!full[u] || !full[v])) {
ans += nodes[i].w;
pa[u] = v;
full[v] |= full[u];
}
}
printf("%d\n", ans);
}
}