Vijos 1776 关押罪犯 【并查集+贪心】

题目:
S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c的冲突事件。每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S城Z市长那里。公务繁忙的Z市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。在详细考察了N名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那么,应如何分配罪犯,才能使Z市长看到的那个冲突事件的影响力最小?这个最小值是多少?
 
分析:
反正只看最大的怨气值,从贪心的方面考虑,我们的目的就是在可能的情况下,尽量把怨气值大的分开。于是首先想到了先排序,从最大的死对头入手。在这个题目中,我们一定要把焦点放在对立或同伴关系上,而不是关注具体谁在哪一个监狱中。于是我们把一对对死对头从大到小分别分开,直到我们发现有一对死对头已经在同一个监狱中,如果要分开他们,就必须放弃之前的分配造成更大的损失,这时该死对头的怨气值就是无论如何也不能减小的最大值了。
此题可以用并查集实现,也可以用二分图,我这里用并查集。
 
下面是参考代码:
 
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std; 
struct cc{int a,b,c;} crime[500000];
int n,m;
int f[500001];
bool comp(const cc &a,const cc &b){return a.c>b.c;}
int find(int x)
{
 if(f[x]!=x) f[x]=find(f[x]);
 else return x;
 return f[x]; 
}

int main(int argc, char** argv) 
{
 cin>>n>>m;
 for(int i=1;i<=m;i++)
  cin>>crime[i].a>>crime[i].b>>crime[i].c;
 for(int i=1;i<=n*2;i++)
  f[i]=i;
 sort(crime+1,crime+1+m,comp);
 for(int i=1;i<=m;i++)
 {
  int x=find(crime[i].a);
  int y=find(crime[i].b);
  if(x==y)
  {
   cout<<crime[i].c;
   return 0;
  }
  f[y]=find(crime[i].a+n);
  f[x]=find(crime[i].b+n);
 }
 cout<<0;
 return 0;
}
View Code

 

posted @ 2017-07-19 16:07  Captain_fcj  阅读(242)  评论(0编辑  收藏  举报