关押罪犯(并查集)

题干:

  $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$ 。

  数据保证 $1<=a_j<b_j<N$ , $0<c_j<=1000000000$,且每对罪犯组合只出现一次。

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

题解:

  这道题要求最大的冲突值最小,又有两个人的怨气值,我们就可以想到用并查集来判断某两个人的关系情况。

  有一个贪心:先处理怨气值较大的几对,再处理较小的;若无法满足题意,就直接输出即可

  在处理敌对关系时,我们可以相应的给这 $n$ 个点建一个虚点,虚点来存是否是敌人,若两人是敌对关系,就分别连上互相的敌对点。

  如果两个点的父节点一样,就说明有一个点在 $1$ 监狱也不行,在 $2$ 监狱也不行,它就是最终答案。

  (其实相当于判断二分图)

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define $ 230100
 5 #define int long long
 6 using namespace std;
 7 int m,n,k,t,dad[$];
 8 struct tree{
 9     int x,y,val;
10     friend bool operator < (const tree &a,const tree &b){
11         return a.val>b.val;
12     }
13 }a[$];
14 inline int find(int x){    return (dad[x]==x)?(x):(dad[x]=find(dad[x]));    }
15 signed main(){
16     scanf("%lld%lld",&n,&m);
17     for(register int i=1;i<=n*2+2;++i) dad[i]=i;
18     for(register int i=1;i<=m;++i)
19         scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].val);
20     sort(a+1,a+m+1);
21     for(register int i=1,x,y,val,dadx,dady;i<=m;++i){
22         x=a[i].x, y=a[i].y, val=a[i].val;
23         dadx=find(x), dady=find(y);
24         if(dadx==dady){    printf("%lld\n",val); return 0;    }
25         dad[dadx]=find(y+n);
26         dad[dady]=find(x+n);
27     }
28     puts("0");
29 }
View Code
posted @ 2019-08-04 21:45  OI_zzyy  阅读(403)  评论(3编辑  收藏  举报