Luogu 1525 【NOIP2010】关押罪犯 (贪心,并查集)

Luogu 1525 【NOIP2010】关押罪犯 (贪心,并查集)

Description

S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c的冲突事件。每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S城Z市长那里。公务繁忙的Z市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。
在详细考察了N名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那么,应如何分配罪犯,才能使Z市长看到的那个冲突事件的影响力最小?这个最小值是多少?

Input

每行中两个数之间用一个空格隔开。
第一行为两个正整数N和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。
接下来的M行每行为三个正整数aj,bj,cj,表示aj号和bj号罪犯之间存在仇恨,其怨气值为cj。
数据保证1<=aj<bj<N,0<cj<=1,000,000,000,且每对罪犯组合只出现一次。

Output

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

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

Http

Luogu:https://www.luogu.org/problem/show?pid=1525

Source

贪心,并查集

解决思路

首先根据贪心的思路,尽量把影响力大的两个人排在不同的监狱,所以我们从最大向最小拍,直到排到无法分在两个监狱,此时的结果即为最小值。
这个贪心为什么是对的呢?假设我们有现在冲突的两个人,如果要保证这两个人不冲突,一定要拆散前面排好至少一组关系,而前面的影响力是更大的,所以更换前面的不划算。所以这个贪心策略是正确的。
接下来我们考虑如何维护这个不在同一个监狱的关系。首先分析一下,两个人AB不能分在同一个监狱,那么也就意味着A分在与B有冲突的人的监狱,而B分在与A有冲突的人的监狱,那么我们可以看做是把A与B的潜在敌人分在一起。
这个东西是可以用并查集维护的。我们设人i表示这个人,i+n表示人i的潜在敌人(总共n个人),那么如果i与j有冲突,那么合并i与j+n,j与i+n,相当于把i与j的潜在敌人合并,而把j与i的潜在敌人合并。那么不能放的条件就是i与j在同一个集合,此时的影响力就是最终的解。
另:注意判断无解的情况,此时输出0

代码

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

const int maxN=30000*2;
const int maxM=100101;
const int inf=2147483647;

class Edge
{
public:
    int u,v,w;
};

bool operator < (Edge A,Edge B)
{
    return A.w>B.w;
}

int n,m;
Edge E[maxM];
int Mayuri[maxN];//并查集

int Find(int x);

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n*2;i++)//初始化并查集
        Mayuri[i]=i;
    for (int i=1;i<=m;i++)
        scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].w);
    sort(&E[1],&E[m+1]);//排序,从大到小
    bool is_outp=0;
    for (int i=1;i<=m;i++)
    {
        int f1=Find(E[i].u);
        int f2=Find(E[i].v);
        if (f1!=f2)
        {
            Mayuri[Find(E[i].u+n)]=Find(E[i].v);//与潜在敌人合并
            Mayuri[Find(E[i].v+n)]=Find(E[i].u);
        }
        else
        {
            cout<<E[i].w<<endl;
            is_outp=1;
            break;
        }
    }
    if (is_outp==0)//注意无解的情况
        cout<<0<<endl;
    return 0;
}


int Find(int x)
{
    if (Mayuri[x]!=x)
        Mayuri[x]=Find(Mayuri[x]);
    return Mayuri[x];
}
posted @ 2017-09-04 21:12  SYCstudio  阅读(427)  评论(0编辑  收藏  举报