国王的烦恼

题意:

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

分析:

看到这个题的时候第一念头并没有想到并查集,(可能我太菜啦),我的第一个想法是,找到相同长度的边,算一天,其他不同的边,依次判断边的两个顶点是否还可以到达,如果可以那么继续删除其他的边,直到不能到达,结果就加一。但是实现起来发现特别麻烦的dfs,时间复杂度也高

看了大佬的题解,总结如下,将边权按照从大到小排序,遍历,每次合并边的两个顶点,如果说已经被合并过,那么说明这个边已经被计算了,就不用算了,如果说和前面天数一样的话,那么就是相当于这一天可以发生多次抗议,但是算一天,所以也不用计算了。

代码实现:

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e4+10;
const int M = 1e5+10;

struct edge{
    int a,b;
    int val;
    bool operator < (const edge& a) const{
        return this->val>a.val;
    }
};

int fa[N];

int find(int a){
    if(a==fa[a])return a;
    return fa[a]=find(fa[a]);
}
edge edges[M];

void un(int a,int b){
    int af=find(a);
    int bf=find(b);
    fa[af]=bf;
}

int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=0;i<m;i++){
        cin>>edges[i].a;
        cin>>edges[i].b;
        cin>>edges[i].val;
    }
    sort(edges,edges+m);
    int lastv=-1;
    int ans=0;
    for(int i=0;i<m;i++){
        int a=edges[i].a;
        int b=edges[i].b;
        int v=edges[i].val;
        int af=find(a);
        int bf=find(b);
        if(af!=bf){
            un(a,b);
        }
        if(af!=bf&&lastv!=v){
            ans++;
            lastv=v;
        }
    }
    cout<<ans<<endl;
}

还是要多刷图论,数论。

posted @ 2020-07-28 16:55  kstranger  阅读(85)  评论(0)    收藏  举报