codevs5971: 打击犯罪
题目描述 Description
某个地区有n(n<=1000)个犯罪团伙,当地警方按照他们的危险程度由高到低给他们编号为1-n,他们有些团伙之间有直接联系,但是任意两个团伙都可以通过直接或间接的方式联系,这样这里就形成了一个庞大的犯罪集团,犯罪集团的危险程度唯一由集团内的犯罪团伙数量确定,而与单个犯罪团伙的危险程度无关(该犯罪集团的危险程度为n)。现在当地警方希望花尽量少的时间(即打击掉尽量少的团伙),使得庞大的犯罪集团分离成若干个较小的集团,并且他们中最大的一个的危险程度不超过n/2。为达到最好的效果,他们将按顺序打击掉编号1到k的犯罪团伙,请编程求出k的最小值。
输入描述 Input Description
第一行一个正整数n。接下来的n行每行有若干个正整数,第一个整数表示该行除第一个外还有多少个整数,若第i行存在正整数k,表示i,k两个团伙可以直接联系。
输出描述 Output Description
一个正整数,为k的最小值
样例输入 Sample Input
7
2 2 5
3 1 3 4
2 2 4
2 2 3
3 1 6 7
2 5 7
2 5 6
样例输出 Sample Output
1
数据范围及提示 Data Size & Hint
n<=1000
输出1(打击掉红色团伙)
题解
不容易删点,所以考虑倒着加点,找到一组不满足要求了输出即可。1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define maxn 1010 5 #define inf 1<<29 6 using namespace std; 7 int fa[maxn],n,m,ans=inf,siz[maxn],ecnt,tt,head[maxn]; 8 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} 9 struct edge{ 10 int u,v,next; 11 }E[maxn*maxn]; 12 void add(int u,int v) 13 { 14 E[++ecnt].u=u; 15 E[ecnt].v=v; 16 E[ecnt].next=head[u]; 17 head[u]=ecnt; 18 } 19 int main() 20 { 21 scanf("%d",&n); 22 for(int i=1 ; i<=n ; ++i ) 23 { 24 fa[i]=i; 25 siz[i]=1; 26 scanf("%d",&m); 27 for(int j=1 ; j<=m ; ++j) 28 { 29 scanf("%d",&tt); 30 add(i,tt); 31 add(tt,i); 32 } 33 } 34 for(int i=n ; i>=1 ; --i) 35 { 36 int fx=find(i); 37 for(int j=head[i] ; j ; j=E[j].next ) 38 { 39 int v=E[j].v; 40 if(v<i)continue; 41 int fy=find(v); 42 if(fx!=fy) 43 { 44 fa[fy]=fx; 45 siz[fx]+=siz[fy]; 46 if(siz[fx]>n/2) 47 { 48 printf("%d",i); 49 return 0; 50 } 51 } 52 } 53 } 54 return 0; 55 }