打击犯罪
【问题描述】
某个地区有n(n<=1000)个犯罪团伙,当地警方按照他们的危险程度由高到低给他们编号为1-n,他们有些团伙之间有直接联系,但是任意两个团伙都可以通过直接或间接的方式联系,这样这里就形成了一个庞大的犯罪集团,犯罪集团的危险程度唯一由集团内的犯罪团伙数量确定,而与单个犯罪团伙的危险程度无关(该犯罪集团的危险程度为n)。现在当地警方希望花尽量少的时间(即打击掉尽量少的团伙),使得庞大的犯罪集团分离成若干个较小的集团,并且他们中最大的一个的危险程度不超过n/2。为达到最好的效果,他们将按顺序打击掉编号1到k的犯罪团伙,请编程求出k的最小值。
【输入格式】
第一行一个正整数n
接下来的n行每行有若干个正整数,第一个整数表示该行除第一个外还有多少个整数,若第i行存在正整数k,表示i,k两个团伙可以直接联系
【输出格式】
一个正整数,为k的最小值
【样例】
7
2 2 5
3 1 3 4
2 2 4
2 2 3
3 1 6 7
2 5 7
2 5 6
输出1(打击掉红色团伙)
思路
简单的暴力+并查集的小小改动。。。
反过来从全部集团都被干掉开始往前搜
构造有n这个点时,判断与n相连的点是否存在,存在就合并+统计集合里点的数目,因为通过观察样例可以知道1和2有直接联系的话,那2和1也有直接联系,那么我们在只需要合并和统计与新构造的点相连的点就可以了
然后如上构造n-1,n-2……直到新构造的点出现后的点集合有数目超过n div 2 就break然后输出答案
1 program black; 2 const 3 inf='black.in'; 4 outf='black.out'; 5 var 6 father,ok:array[0..1000] of longint; 7 a:array[1..1000,0..1000] of longint; 8 ch:array[1..1000] of boolean; 9 i,n,t,sum,count,t1,t2,j:longint; 10 11 function find(apple:longint):longint; 12 begin 13 if father[apple]<>0 then begin 14 father[apple]:=find(father[apple]); 15 exit(father[apple]); 16 end 17 else exit(apple); 18 end; 19 20 procedure union(a,b:longint); 21 begin 22 t1:=find(a); 23 t2:=find(b); 24 if t1<>t2 then begin 25 father[t2]:=t1; 26 ok[t1]:=ok[t1]+ok[t2]; 27 ok[t2]:=0; 28 end; 29 end; 30 31 begin 32 assign(input,inf); 33 assign(output,outf); 34 reset(input); rewrite(output); 35 36 readln(n); 37 for i:= 1 to n do 38 begin 39 read(a[i,0]); 40 for j:= 1 to a[i,0] do 41 read(a[i,j]); 42 end; 43 count:=n+1; 44 repeat 45 dec(count); 46 ch[count]:=true; 47 j:=count; ok[j]:=1; 48 for i:=1 to a[j,0] do 49 if ch[a[j,i]] then 50 union(j,a[j,i]); 51 sum:=0; 52 if ok[j]>n div 2 then break; 53 until count=0; 54 55 writeln(count); 56 57 close(input); 58 close(output); 59 end.