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;
}

时间: 2024-07-31 15:44:54

Vijos 1776 关押罪犯 【并查集+贪心】的相关文章

洛谷P1525 关押罪犯 并查集

无冲突 输出 0 洛谷P1525 关押罪犯 并查集 用拆点法 将一个点拆成两份 一个点和 x 的朋友相连 一个点和 x的敌人相连 若 x 与 y 是敌人 因为只有两个阵营 所以满足敌人的敌人就是朋友 然后 x 连向 y 的敌人 y 连向 x 的敌人 因为这是双向边 所以 y的朋友就是x的敌人就不用连了 如果某一时刻 getfather(e[ i ].from)==getfather(e[ i ].to) 这说明两个点已经是敌人关系的两个人 通过朋友关系连上了 那就结束了 1 #include <

洛谷P1525关押罪犯——并查集

题目:https://www.luogu.org/problemnew/show/P1525 并查集+贪心,从大到小排序,将二人分在不同房间,找到第一个不满足的即为答案. 代码如下: #include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m,fa[20005],ans,ct,d[20005]; struct N{ int hd,to,w; }edge[1000

Vijos 1776 关押罪犯

这道题看了网上好多的题解,用的都是二分图的算法,但是自己却用的是贪心加并查集的做法.二分图的做法其实我并不会,是不是很神奇. 实际上贪心的算法很好想,只要先用一个结构体维护两个人的怒气值,然后从小到大排序.再从小到大搜一遍.时间复杂度大概是(nlogn+n)总时154ms,基本上是C++中最快的了.... 在搜的过程中,就需要用到并查集了.因为需要尽量把不会产生怨气值的罪犯关在一起,所以首先维护一个名为fa的数组,记录的是两个监狱中所关押的犯人,在从小往大搜的过程中,假设是第i条关系,如果这条关

NOIP2010关押罪犯[并查集|二分答案+二分图]

题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多.如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件. 每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里.公务繁忙的Z 市长只会去看列表

[noip2010]关押罪犯 并查集

第一次看的时候想到了并查集,但是不知道怎么实现: 标解,f[i]表示i所属的集合,用f[i+n]表示i所属集合的补集,实现的很巧妙,可以当成一个使用并查集的范例: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<map> 6 #include<ctime> 7 #include<vector>

codevs 1069 关押罪犯 并查集

很有意思的一道题.刚开始看不出这是道并查集,后来看了题解才会做,就是把要分开的囚犯放在同个集合里,表示这两个囚犯不在同一间监狱,但不是直接合并,例如1和2要分开,则1和2’.1’和2合并(x’为x的虚点),同个集合中实点和虚点分属于两间监狱(即x’与y在不同监狱):再例如,1和2,2和3要分开,则1和2’合并,2’和3合并,那么1和3会在同一间监狱,1’和2合并,2和3’合并,那么2就在另一间监狱.这样一来整道题的思路就呼之欲出了:按仇恨值从大到小分开每对囚犯,若出现无法分开的情况(即已在同一个

P1525 关押罪犯 并查集

题目链接:https://www.luogu.org/problemnew/show/P1525 一道很难想到思路的题,还可以用二分图染色法,但我们只考虑并查集 要使得冲突最小,首先我们应该让冲突大的尽可能的不在同一个监狱 如果两个相互冲突的人都与第三个人冲突,那么应优先让冲突大的在不同的监狱 那么冲突小的冲突就是不可避免地冲突 如果整个过程都按照冲突的大小从大到小进行的话第一个不可避免的冲突就是将会发生的冲突中最大的一个 用并查集来实现的话,就是将敌人的敌人与自己放在同一个集合中,在同一个集合

HDU 1051 并查集+贪心

Wooden Sticks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11694    Accepted Submission(s): 4837 Problem Description There is a pile of n wooden sticks. The length and weight of each stick ar

zoj 3659 Conquer a New Region 并查集+贪心

点击打开链接题目链接 Conquer a New Region Time Limit: 5 Seconds      Memory Limit: 32768 KB The wheel of the history rolling forward, our king conquered a new region in a distant continent. There are N towns (numbered from 1 to N) in this region connected by s