鏈接
http://codeforces.com/contest/875/problem/F
題意
給n個白點,m個黑點,其中第i個黑點和兩個白點有邊權爲
思路
貪心,之前自己寫了一個按邊貪心的,結果很容易就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);
}
}