- 题库 :一本通
- 题号 :1386
- 题目 :打击犯罪
- link :http://ybt.ssoier.cn:8088/problem_show.php?pid=1386
O(n3)思路 :此题数据太水,n3就能卡过。暴力枚举1 ~ n,每次都重新将并查集初始化并且按题目输入将所有 >= k(1 <= k <= n)的点合并(及打击掉1 ~ k的犯罪团伙,他们不合并)。从1 ~ n枚举直到找到最小的k满足所有犯罪团伙中的最大的一个的危险程度不超过n / 2,直接输出k。
code :
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 using namespace std; 4 int n, fa[1001], size[1001], p[1001], q[1001][1001];//记录下输入数据 5 inline int find(int x)//搜索 6 { 7 return x == fa[x] ? fa[x] : fa[x] = find(fa[x]); 8 } 9 inline void unity(int x, int y)//按秩合并 + 路径压缩 10 { 11 int r1 = find(x); 12 int r2 = find(y); 13 if(size[r1] < r2) 14 { 15 fa[r1] = r2; 16 size[r2] += size[r1]; 17 } 18 else 19 { 20 fa[r2] = r1; 21 size[r1] += size[r2]; 22 } 23 return; 24 } 25 inline void init(int x) 26 { 27 for(register int i = 1; i <= n; ++i) 28 { 29 fa[i] = i; 30 size[i] = 1; 31 } 32 for(register int i = x + 1; i <= n; ++i)//重新将没被打击掉的犯罪团伙之间的联系连接起来 33 { 34 for(register int j = 1; j <= p[i]; ++j) 35 { 36 if(q[i][j] > x && find(i) != find(q[i][j]))//被联系的犯罪团伙也得 > x 37 { 38 unity(i, q[i][j]); 39 } 40 } 41 } 42 return; 43 } 44 inline int check()//判断犯罪团伙中最大的一个是否 > n / 2 45 { 46 for(register int i = 1; i <= n; ++i) 47 { 48 if(size[fa[i]] > n / 2) 49 { 50 return 0; 51 } 52 } 53 return 1; 54 } 55 signed main() 56 { 57 scanf("%d", &n); 58 for(register int i = 1; i <= n; ++i) 59 { 60 scanf("%d", &p[i]); 61 for(register int j = 1; j <= p[i]; ++j) 62 { 63 scanf("%d", &q[i][j]); 64 } 65 } 66 for(register int i = 0; i <= n; ++i) 67 { 68 init(i);//初始化 69 if(check())//判断 70 { 71 printf("%d", i); 72 return 0; 73 } 74 } 75 return 0; 76 }
O(n2)正解思路 :我们发现每次都重新输入过于多余,可以倒着输入,判断犯罪团伙中最大的一个是否 > n / 2,直到犯罪团伙中最大的一个 > n / 2时,输出k(k从n ~ 1枚举),表示不打击掉k就不行了。
code :
1 //和O(n ^ 3)的注释基本差不多 2 #include <bits/stdc++.h> 3 #define INF 0x3f3f3f3f 4 using namespace std; 5 int n, fa[1001], size[1001], p[1001], q[1001][1001]; 6 inline int find(int x) 7 { 8 return x == fa[x] ? fa[x] : fa[x] = find(fa[x]); 9 } 10 inline void unity(int x, int y) 11 { 12 int r1 = find(x); 13 int r2 = find(y); 14 if(size[r1] < r2) 15 { 16 fa[r1] = r2; 17 size[r2] += size[r1]; 18 } 19 else 20 { 21 fa[r2] = r1; 22 size[r1] += size[r2]; 23 } 24 return; 25 } 26 inline void init(int x) 27 { 28 for(register int i = 1; i <= p[x]; ++i) 29 { 30 if(q[x][i] >= x && find(x) != find(q[x][i])) 31 { 32 unity(x, q[x][i]); 33 } 34 } 35 return; 36 } 37 inline int check() 38 { 39 for(register int i = 1; i <= n; ++i) 40 { 41 if(size[fa[i]] > n / 2) 42 { 43 return 0; 44 } 45 } 46 return 1; 47 } 48 signed main() 49 { 50 scanf("%d", &n); 51 for(register int i = 1; i <= n; ++i) 52 { 53 fa[i] = i; 54 size[i] = 1; 55 } 56 for(register int i = 1; i <= n; ++i) 57 { 58 scanf("%d", &p[i]); 59 for(register int j = 1; j <= p[i]; ++j) 60 { 61 scanf("%d", &q[i][j]); 62 } 63 } 64 for(register int i = n; i >= 1; --i)//倒着整 65 { 66 init(i); 67 if(!check())//如果不打击掉当前犯罪团伙就不行了 68 { 69 printf("%d", i);//最小打击值 70 return 0; 71 } 72 } 73 return 0; 74 }