首页 > 代码库 > 10 noip 关押罪犯 解题报告
10 noip 关押罪犯 解题报告
S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极
不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨
气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之
间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并
造成影响力为c 的冲突事件。
每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,
然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,
如果影响很坏,他就会考虑撤换警察局长。
在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在
两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只
要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那
么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是少?
第一行为两个正整数N 和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。
接下来的M 行每行为三个正整数aj,bj,cj,表示aj 号和bj 号罪犯之间存在仇恨,其怨气值为cj。数据保证,且每对罪犯组合只出现一次。
共1 行,为Z 市长看到的那个冲突事件的影响力。如果本年内监狱
中未发生任何冲突事件,请输出0。
4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884
3512
罪犯之间的怨气值如下面左图所示,右图所示为罪犯的分配方法,市长看到的冲突事件
影响力是3512(由2 号和3 号罪犯引发)。其他任何分法都不会比这个分法更优。
【数据范围】
对于30%的数据有N≤ 15。
对于70%的数据有N≤ 2000,M≤ 50000。
对于100%的数据有N≤ 20000,M≤ 100000。
先谈一下储存方式吧,这个题目肯定不能建二维数组,于是我选择了记录类型。
这个题目的做法很多,我采取的是并查集的做法,制作了两个数组,一个用来储存他的敌人,也就是肯定不和他在同一个监狱的人,另一个是他的狱友。
先将怒气值从大到小排序一遍,从大到小进行判断。如果两个人都没有敌人,那么就把对方作为自己的敌人。如果对方已经有敌人了,那么自己和对方的敌人就要成为狱友了。如果两个人是狱友,那么他们的怒气值就是答案了。
判断两个人是不是狱友,用并查集就可以。因为我们不断规避大的怒气值的出现,一旦出现了一个怒气值无法规避,那么,这个怒气值就是该题目的答案。
代码风格略渣,不喜勿喷。
1 type 2 re=record //记录格式 3 x:longint; 4 y:longint; 5 k:longint; 6 end; 7 var 8 x,y,i,j,n,m,ans,k,t:longint; 9 a:array[1..100000]of re;10 b,c:array[1..20000]of longint; //b储存敌人 c储存狱友11 12 function union(k:longint):longint; //并查集13 begin14 if c[k]=k then exit(k)15 else exit(union(c[k]));16 end;17 18 procedure hb(x,y:longint); //处理两个人信息19 begin20 if b[x]=0 then b[x]:=y;21 if b[y]=0 then b[y]:=x;22 c[union(y)]:=union(b[x]);23 c[union(x)]:=union(b[y]);24 end;25 26 procedure qsort(h,t:longint);27 var28 i,j,x:longint;29 k:re;30 begin31 i:=h;32 j:=t;33 x:=a[(h+t) div 2].k;34 while (i<j) do35 begin36 while (a[i].k>x) do inc(i);37 while (a[j].k<x) do dec(j);38 if (i<=j) then39 begin40 k:=a[i];41 a[i]:=a[j];42 a[j]:=k;43 inc(i);44 dec(j);45 end;46 end;47 if (i<t) then qsort(i,t);48 if (h<j) then qsort(h,j);49 end;50 51 begin52 readln(n,m);53 for i:=1 to n do54 c[i]:=i;55 for i:=1 to m do56 begin57 readln(x,y,k);58 a[i].x:=x;59 a[i].y:=y;60 a[i].k:=k;61 end;62 qsort(1,m);63 ans:=0;64 for i:=1 to m do65 if union(a[i].x)=union(a[i].y) then //判断两人是否是狱友66 begin ans:=a[i].k; break; end67 else68 hb(a[i].x,a[i].y);69 writeln(ans); //如果到最后都没发生冲突,ans就等于070 end.
10 noip 关押罪犯 解题报告