【并查集】【P1525】关押罪犯

传送门

Description

Input

Output

Sample Input

4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884

Sample Output

3512

Hint

Solution

  非常显然的并查集题目,在本题中,对于每个罪犯i,维护两个信息:必须要和他关在一起的罪犯的集合,以及和他有仇的罪犯的集合,由于监狱只有两个,所以和他有仇的罪犯一定被关在同一个集合里面。sort一遍贪心从上到下扫描。对于不得不管起来的两个有仇的人即为答案。

Code

#include<cstdio>
#include<algorithm>
namespace read{
    void imop(int&x){
        char ch=getchar();
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9')   x=x*10+ch-'0',  ch=getchar();
        return;
    }
    void op(int&x){
        char ch=getchar();
        int f=1;
        while(ch<'0'||ch>'9'){
            if(ch=='-') f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')   x=x*10+ch-'0',  ch=getchar();
        x*=f;
        return;
    }
}
namespace fusu{
    const int maxn = 20010 , maxm = 100010;
    struct Crim{
        int a,b,value;
    };
    Crim criminal[maxm];
    int n,m;
    inline bool cmp(Crim a,Crim b){return a.value<b.value;}
    int frog[maxn],enemy[maxn];
    inline int find(int x){
        if(frog[x]^x)    frog[x]=find(frog[x]);
        return frog[x];
    }
    void gather(int a,int b){
        int fa=find(frog[a]),fb=find(frog[b]);
        frog[fa]=fb;
        return;
    }
    void beginning(){
        for(int i=1;i<=n;++i)
            frog[i]=i;
        return;
    }
    int doit(){
        read::imop(n);read::imop(m);
        for(int i=1;i<=m;++i){
            read::imop(criminal[i].a);
            read::imop(criminal[i].b);
            read::imop(criminal[i].value);
        }
        std::sort(criminal+1,criminal+1+m,cmp);
        beginning();
        do{
            int fa=find(frog[criminal[m].a]),fb=find(frog[criminal[m].b]);
            if(!(fa^fb)){
                printf("%d\n",criminal[m].value);
                return 0;
            }
            if(!enemy[criminal[m].a])    enemy[criminal[m].a]=criminal[m].b;
                else gather(enemy[criminal[m].a],criminal[m].b);
            if(!enemy[criminal[m].b])    enemy[criminal[m].b]=criminal[m].a;
                else gather(enemy[criminal[m].b],criminal[m].a);
            --m;
        }while(m);
        printf("0\n");
        return 0;
    }
}
int main(){
    return fusu::doit();
}

Summary

对于并查集中的补集法,对于每个个体记录多个信息,在合并时合并多个信息即可。

posted @ 2018-06-19 20:47  一扶苏一  阅读(335)  评论(0编辑  收藏  举报