洛谷 P1525 关押罪犯 并查集

洛谷 P1525 关押罪犯 并查集

题解:

(1)我们需要先对所有边的权值(也就是矛盾值)按照权值从大到小的顺序进行排序,为什么要排序呢,因为我们需要尽量把两个仇恨值大的罪犯分到不同的集合,所以要先对他们进行处理。
(2)然后这里有一个原则,就是敌人的敌人可能是朋友,怎样理解这句话呢?可以理解为自己的两个敌人可能是朋友我们把自己的两个敌人分到一个集合中,自己在一个集合,他们之间可能不存在矛盾,此时就是最优化的选择
(3)当我们处理一条边的两个顶点时,若此时它们已经在一个集合中,说明矛盾是不可避免的,这时就可以停止,直接输出这条边的权值即可。
(4)最后注意输出0的情况。

代码如下:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cmath>
#include<queue>
#include<cstring>
#include<vector>
#include<map>
#define MAX 20005
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;

int n,m,fa[MAX],enemy[MAX];

struct edge{
    int w;//边的权值
    int s;//边的起点
    int f;//边的终点
    edge(int ss,int ff,int ww){
        s=ss;
        f=ff;
        w=ww;
    }
    bool operator < (const edge &a) const{//最大值优先
        return w>a.w;
    }
};

int findfather(int x){
    if(x!=fa[x]){
        return findfather(fa[x]);
    }else{
        return fa[x];
    }
}

void _union(int a,int b){
    int aa=findfather(a);
    int bb=findfather(b);
    if(aa!=bb){
        fa[aa]=bb;
    }
}

vector<edge> e;

int main(){
    scanf("%d%d",&n,&m);
    int a,b,c;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&a,&b,&c);
        edge tmp(a,b,c);
        e.push_back(tmp);
    }
    sort(e.begin(),e.end());
    for(int i=0;i<MAX;i++){//初始化
        fa[i]=i;
    }
    for(int i=0;i<m;i++){
        int t1=findfather(e[i].s),t2=findfather(e[i].f);
        if(t1==t2){//如果s和f已经在同一集合,则直接结束
            printf("%d",e[i].w);
            return 0;
        }
        int s=e[i].s,f=e[i].f;
        //自己的两个敌人可能是朋友,其实也就是敌人的敌人就是朋友
        if(!enemy[s]) enemy[s]=f;
        else _union(enemy[s],f);

        if(!enemy[f]) enemy[f]=s;
        else _union(enemy[f],s);
    }
    printf("0");//说明不存在矛盾
    return 0;
}
发布了253 篇原创文章 · 获赞 15 · 访问量 7968

猜你喜欢

转载自blog.csdn.net/weixin_44123362/article/details/104053763