nyoj 925 国王的烦恼 (并查集)

国王的烦恼

时间限制: 3000 ms  |  内存限制:65535 KB
难度: 2
 
描述

    C国由n个小岛组成,为了方便小岛之间联络,C国在小岛间建立了m座大桥,每座大桥连接两座小岛。两个小岛间可能存在多座桥连接。然而,由于海水冲刷,有一些大桥面临着不能使用的危险。如果两个小岛间的所有大桥都不能使用,则这两座小岛就不能直接到达了。然而,只要这两座小岛的居民能通过其他的桥或者其他的小岛互相到达,他们就会安然无事。但是,如果前一天两个小岛之间还有方法可以到达,后一天却不能到达了,居民们就会一起发起抗议。

    现在C国的国王已经知道了每座桥能使用的天数,超过这个天数就不能使用了。现在他想知道居民们一共会发起多少次抗议。

 
输入
  多组测试数据。
  每组数据先输入两个正整数n和m。
  接下来m行,每行三个整数a, b, t,分别表示该座桥连接a号和b号两个小岛,能使用t天。小岛的编号从1开始递增。(1≤n≤10000,1≤m≤100000,1<=a,b<=n,1≤t≤100000)
输出
  输出一个整数,表示居民们发起抗议的次数。
样例输入
4 4
1 2 2
1 3 2
2 3 1
3 4 3
样例输出
2
提示
对于样例:
第一天后2和3之间的桥不能使用,不影响。
第二天后1和2之间,以及1和3之间的桥不能使用,居民们会抗议。
第三天后3和4之间的桥不能使用,居民们会抗议。
/**
    分析:该题是,判断第i天的非连通区域和第i+1天的非连通区域
            若第i+1天的非连通区域比第i天的非连通区域多 说明:桥断了、居民抗议、cnt ++
            
            所以我们可以逆向思维 <断桥  <==>  修桥>(将数据按照天数由大到小排列):
                若将两个桥 my_join 的时候桥没有连通 cnt ++  <同时要考虑是否和上一个数据是同一天(因为居民每天最大抗议一次)> 
    数据结构:并查集
    模板:
        pre [100005];
        void init () {
            for (int i = 1; i <= n; ++ i) {
                pre [i] = i;
            }
            return ;
        } 
        
        int my_find (int x) {
            int n = x;
            while (n != pre [n]) {
                n = pre [n];
            }
            int i = x, j;
            while (n != pre [i]) {
                j = pre [i];
                pre [i] = n;
                i = j;
            }
        }
        
        bool my_join (int a, int b) {
            int n1 = my_find (a), n2 = my_find (b);
            if (n1 != n2) {
                pre [n1] = n2;
                return true;
            } else {
                return false;
            }
        }
**/ 

C/C++代码实现:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <stack>
#include <queue>
#include <map>

using namespace std;

int n, m, pre [10005];

struct node {
    int x, y, w;
}P [100005];

void init () {
    for (int i = 1; i <= n; ++ i) {
        pre [i] = i;
    }
    return ;
}

bool cmp (node a, node b) {
    return a.w > b.w;
}

int my_find (int x) {
    int n = x;
    while (n != pre [n]) {
        n = pre [n];
    }
    int i = x, j;
    while (n != pre [i]) {
        j = pre [i];
        pre [i] = n;
        i = j;
    }
    return n;
}

bool my_join (int a, int b) {
    int n1 = my_find (a), n2 = my_find (b);
    if (n1 != n2) {
        pre [n1] = n2;
        return true;
    }
    return false;
}

int main () {
    while (~scanf ("%d%d", &n, &m)) {
        init();
        int cnt = 0, my_first = -1;
        for (int i = 0; i < m; ++ i) {
            scanf ("%d%d%d", &P[i].x, &P[i].y, &P[i].w);
        }
        sort (P, P + m, cmp);
        for (int i = 0; i < m; ++ i) {
            if (my_join (P[i].x, P[i].y) && my_first != P[i].w) {
                ++ cnt;
                my_first = P[i].w; // 每一天最多抗议1次 
            }
        }
        printf ("%d\n", cnt);
    }
} 

猜你喜欢

转载自www.cnblogs.com/GetcharZp/p/8974663.html