【洛谷】P1525 关押罪犯

洛谷P1525 关押罪犯

题目描述
S 城现有两座监狱,一共关押着 N 名罪犯,编号分别为 1-N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为 c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为 c 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到 S 城 Z 市长那里。公务繁忙的 Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。

那么,应如何分配罪犯,才能使 Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

输入格式
每行中两个数之间用一个空格隔开。第一行为两个正整数 N,M,分别表示罪犯的数目以及存在仇恨的罪犯对数。接下来的 M 行,每行为三个正整数 a j , b j , c j a_j,b_j,c_j aj,bj,cj,表示 a j a_j aj号和 b j b_j bj 号罪犯之间存在仇恨,其怨气值为 c j c_j cj。数据保证 1 < a j ≤ b j ≤ N , 0 < c j ≤ 1 0 9 11<ajbjN,0<cj109 ,且每对罪犯组合只出现一次。

输出格式
共1行,为Z市长看到的那个冲突事件的影响力。如果本年内监狱未发生任何冲突事件,请输出0。

输入#1:

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

输出#1:

3512

题目的大意是n个人,要分成了两个集合,然后给定某些两个人在一起会产生一个影响数值;现在要使得产生的影响最大值最小。
思路其实一看就知道了,既然只看最大的影响值,就贪心处理,把所有的关系按影响从大到小排序,最大影响值的两个人分在两个集合,然后第二大影响值类似处理…直到某一个影响值发现两个人已经在一个集合了,这时候就没办法了,这个影响值就是结果。集合可以用并查集实现,这种类似于二分图的题应该怎么处理呢?
一个比较方便的方法是用一个enemy数组。当处理一对罪犯x和y的时候,如果x没有enemy,那么给其添加;如果x已经有enemy了,就将其enemy和y并入一个集合,表示要关在一个监狱里。每次处理x和y时首先看他们在不在一个集合里,如果已经在了,那没事了,结束了。
当初看这个解法的时候有一个疑问,处理x和y的时候,如果没有enemy添加入enemy肯定没问题,但如果假设x有敌人z,那么就要把y和z加入同一个集合,但假如说y和z已经是敌人了,这里也不会直接退出,那怎么办?
其实这是不可能的。假如y和z已经是敌人了,然后x有敌人z说明(x,z)已经处理过,x和y都是z的敌人,已经在一个集合里了,那么处理x和y的时候最开始就发现退出了。代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int n,m;
int p[20010],enemy[20010];
struct relation{
    int x,y,effect;
}relations[100010];

int findp(int i){
    if(p[i]!=i){
        p[i]=findp(p[i]);
    }
    return p[i];
}
void merge(int a,int b){
    int pa=findp(a),pb=findp(b);
    p[pa]=pb;
}
int cmp(relation a,relation b){
    return a.effect>b.effect;
}
int main(){
    memset(relations,0,sizeof(relations));
    cin>>n>>m;
    for(int i=1;i<=n;i++) p[i]=i;
    for(int i=0;i<m;i++) cin>>relations[i].x>>relations[i].y>>relations[i].effect;
    sort(relations,relations+m,cmp);
    for(int i=0;i<m+1;i++){
        if(findp(relations[i].x)==findp(relations[i].y)){
            cout<<relations[i].effect;
            break;
        }
        if(!enemy[relations[i].x]){
            enemy[relations[i].x]=relations[i].y;
        }
        else{
            merge(relations[i].y,enemy[relations[i].x]);
        }
        if(!enemy[relations[i].y]){
            enemy[relations[i].y]=relations[i].x;
        }
        else{
            merge(relations[i].x,enemy[relations[i].y]);
        }
    }
    return 0;
}

你可能感兴趣的:(洛谷,并查集)