博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
codevs 1069 关押罪犯 并查集
阅读量:5050 次
发布时间:2019-06-12

本文共 2625 字,大约阅读时间需要 8 分钟。

1069 关押罪犯

2010年NOIP全国联赛提高组

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
 
题目描述 Description

S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极

不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨

气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之

间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并

造成影响力为c 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,

然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,

如果影响很坏,他就会考虑撤换警察局长。

在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在

两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只

要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那

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

输入描述 Input Description

第一行为两个正整数N 和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。

接下来的M 行每行为三个正整数aj,bj,cj,表示aj 号和bj 号罪犯之间存在仇恨,其怨气值为cj。数据保证且每对罪犯组合只出现一次。

输出描述 Output Description

共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

数据范围及提示 Data Size & Hint

罪犯之间的怨气值如下面左图所示,右图所示为罪犯的分配方法,市长看到的冲突事件

影响力是3512(由2 号和3 号罪犯引发)。其他任何分法都不会比这个分法更优。

【数据范围】

对于30%的数据有N≤ 15。

对于70%的数据有N≤ 2000,M≤ 50000。

对于100%的数据有N≤ 20000,M≤ 100000。

----------------------------------------------------------------------------------------------------------------------------------------------------------

很有意思的一道题。刚开始看不出这是道并查集,后来看了题解才会做,就是把要分开的囚犯放在同个集合里,表示这两个囚犯不在同一间监狱,但不是直接合并,例如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就在另一间监狱。这样一来整道题的思路就呼之欲出了:按仇恨值从大到小分开每对囚犯,若出现无法分开的情况(即已在同一个监狱),则返回这对仇恨值并退出。附上AC代码:

1 #include
2 #include
3 #include
4 #define maxn 233333 5 using namespace std; 6 struct node{ 7 int a,b,c; 8 }; 9 node e[maxn];10 int N,M,fa[maxn];11 int read();12 bool cmp(node,node);13 int getf(int);14 int main(){15 N=read();M=read();16 for(int i=1;i<=N*2;i++)fa[i]=i;17 for(int i=1;i<=M;i++)e[i].a=read(),e[i].b=read(),e[i].c=read();18 sort(e+1,e+M+1,cmp);19 for(int i=1;i<=M;i++){20 int t1=getf(e[i].a),t2=getf(e[i].b);21 if(t1==t2){22 printf("%d",e[i].c);23 return 0;24 }25 fa[t1]=getf(e[i].b+N);26 fa[t2]=getf(e[i].a+N);27 }28 putchar('0');29 return 0;30 }31 int read(){32 int ans=0,f=1;char c=getchar();33 while('0'>c||c>'9'){
if(c=='-')f=-1;c=getchar();}34 while('0'<=c&&c<='9')ans=ans*10+c-48,c=getchar();return ans*f;35 }36 bool cmp(node x,node y){37 return x.c>y.c;38 }39 int getf(int x){40 if(fa[x]==x) return x;41 return fa[x]=getf(fa[x]);42 }
并查集(补集的运用)

 

这道题中的并查集运用了补集的思想(在同一范围内,x的补集为w,y的补集为w,那么x和y会在同一个集合之中),有趣。

转载于:https://www.cnblogs.com/lpl-bys/p/7391117.html

你可能感兴趣的文章
Linux常用命令总结
查看>>
yii模型ar中备忘
查看>>
C#线程入门
查看>>
CSS清除浮动方法
查看>>
JVM内存回收机制简述
查看>>
洛咕 P2480 [SDOI2010]古代猪文
查看>>
js-创建对象的几种方式
查看>>
JDK JRE Java虚拟机的关系
查看>>
2018.11.20
查看>>
word20161215
查看>>
12th week blog
查看>>
dijkstra (模板)
查看>>
python小记(3)
查看>>
编译Linux驱动程序 遇到的问题
查看>>
大型分布式网站架构技术总结
查看>>
HDU 1017[A Mathematical Curiosity]暴力,格式
查看>>
[算法之美] KMP算法的直观理解
查看>>
EntityFramework 性能优化
查看>>
【ASP.NET开发】菜鸟时期的ADO.NET使用笔记
查看>>
android圆角View实现及不同版本号这间的兼容
查看>>