Codeforces Round #441 Div. 1 F. Royal Questions

来源:互联网 发布:a字裙淘宝 编辑:程序博客网 时间:2024/06/03 21:32

链接

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);  }}
原创粉丝点击