Codeforces Round #441 Div. 1 F. Royal Questions

鏈接

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);
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章