Codeforces 1108F(克鲁斯卡尔的理解)

最小生成树会多样的情况是:两个或多个边等长且连通同样的两个并查集块。

所以可以跑一遍克鲁斯卡尔,每次把当前等长的边数出来,注意不要边找边并查,因为有一部分边是正常跑生成树我们也不会要他的,这种直接跳了;还有一些,是因为你选择了第一个边,然后并在一起了,这时扫到后面的边时他自然会被抛弃。而这种比较委屈的、因为先来后到而被抛弃的边的个数,正是本题答案。如果贪心地并查地话,无法区分这个是本来就跳的,还是我们要找的。

 1 const int maxn = 2e5 + 5;
 2 int n, m, f[maxn], ans;
 3 struct Edge {
 4     int u, v, cost;
 5 
 6     bool operator < (const Edge& rhs) const {
 7         return cost < rhs.cost;
 8     }
 9 }e[maxn];
10 
11 inline int getf(int v) { return v == f[v] ? v : f[v] = getf(f[v]); }
12 
13 int main() {
14     read(n), read(m);
15     rep(i, 1, n)    f[i] = i;
16     rep(i, 1, m) {
17         read(e[i].u);
18         read(e[i].v);
19         read(e[i].cost);
20     }
21     sort(e + 1, e + 1 + m);
22     for (int i = 1, j; i <= m; i = j) {
23         for (j = i; j <= m && e[j].cost == e[i].cost; j++);
24         int cnt = 0;
25         rep(k, i, j - 1) {
26             if (getf(e[k].u) != getf(e[k].v))
27                 cnt++;
28         }
29         rep(k, i, j - 1) {
30             if (getf(e[k].u) != getf(e[k].v)) {
31                 f[getf(e[k].u)] = getf(e[k].v);
32                 cnt--;
33             }
34         }
35         ans += cnt;
36     }
37     writeln(ans);
38     return 0;
39 }

 

posted @ 2019-03-29 13:20  AlphaWA  阅读(281)  评论(0编辑  收藏  举报