首页 > 技术文章 > #luogu整理 P1111 修复公路

Cao-Yucong 2020-04-17 13:59 原文

并查集的题

luogu P1111 修复公路

思路

大体题意:给定n个点,一条一条边加到图里面,然后判断什么时候成为一个连通图。我一开始的时候是每增加一条边就重新扫一扫这个图,但是时间复杂度很显然不够用,所以我第一遍就炸了。后来我发现实际上每次加入一条边的时候,判断会不会减少一个连通块就可以。

注意事项:

并查集容易出现的bug:每次合并的时候,代码应该写成这样:

fa[getfa(x)] = getfa(y); 或者
fa[getfa(x)] = y;

因为x的fa可能会链接这其他的点,如果直接更改x的fa,课能会导致他原有的父亲“丢失”。

代码

注释里面的是我第一遍的文件。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct EDGE{
    int x,y,num;
}edge[100009];
bool cmp(EDGE a,EDGE b){
    return a.num < b.num;
}
int fa[100009];
int getfa(int x){
    return x == fa[x] ? x : getfa(fa[x]);
}
int n,m;
int main(){
    cin >> n >> m;
    for(int i = 1;i <= m; i++){
        cin >> edge[i].x >> edge[i].y >> edge[i].num;
    }
    n--;
    sort(edge+1,edge+1+m,cmp);
    for(int i = 1;i <= n; i++){
        fa[i] = i;
    }
    //cout << endl;
    // for(int i = 1;i <= m; i++){
    //     //cout << edge[i].x << ' ' << edge[i].y << ' ' << edge[i].num << endl;
    // }

    // int i = 0;
    // while(i <= m){
    //     i++;
    //     int x = edge[i].x,y = edge[i].y;
    //     while(edge[i].num == edge[i+1].num){
    //         fa[getfa(x)] = getfa(y);
    //         //cout << i << endl;
    //         i++;
    //     }
    //     x = edge[i].x,y = edge[i].y;
    //     fa[getfa(x)] = getfa(y);
    //     bool fd = 0;
    //     for(int j = 1;j <= n; j++){
    //         //cout << fa[j] << ':';
    //     }
    //     //cout << endl;
    //     for(int j = 1;j <= n; j++){
    //         if(getfa(j) != getfa(n)) fd = 1;
    //     }
    //     if(!fd){ cout << edge[i].num << endl; return 0;}
    // }
    for(int i = 1;i <= m; i++){
        // cout << edge[i].x << ' ' << edge[i].y << ' ' << edge[i].num << endl;
        int x = getfa(edge[i].x),y = getfa(edge[i].y);
        if(x != y){fa[x] = y;n--;}
        // cout << x << ':' << y << endl;
        if(n <= 0){cout << edge[i].num << endl;return 0;}
    }
    cout << -1 << endl;
    return 0;
}

推荐阅读