并查集基础 &打击罪犯
并查集基础 真的很基础
题目描述:Description
某个地区有n(n<=1000)个犯罪团伙,当地警方按照他们的危险程度由高到低给他们编号为1-n,他们有些团伙之间有直接联系,但是任意两个团伙都可以通过直接或间接的方式联系,这样这里就形成了一个庞大的犯罪集团,犯罪集团的危险程度唯一由集团内的犯罪团伙数量确定,而与单个犯罪团伙的危险程度无关(该犯罪集团的危险程度为n)。现在当地警方希望花尽量少的时间(即打击掉尽量少的团伙),使得庞大的犯罪集团分离成若干个较小的集团,并且他们中最大的一个的危险程度不超过n/2。为达到最好的效果,他们将按顺序打击掉编号1到k的犯罪团伙,请编程求出k的最小值。
Input Format
第一行一个正整数n。接下来的n行每行有若干个正整数,第一个整数表示该行除第一个外还有多少个整数,若第i行存在正整数k,表示i,k两个团伙可以直接联系。
Output Format
一个正整数,为k的最小值
Sample
样例输入
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
题目分析:
由题可知,我们需要打击1~k个犯罪团伙,来让其最大的总数不超过n/2(n<<1)。
1.如果我们正向遍历并查集的话,就需要在并查集内删点,这个操作对并查集并不是很友好。所以可以考虑另外一种方法。
2.既然要打击1~k的罪犯,我们不如从第n个团伙开始建立集合,每次加边时判断一下是否满足(<=n/2),直到不能满足题意为止。
AC code:
#include<bits/stdc++.h> using namespace std; #define s(n) scanf("%d",&n) int n,m,a[1010][1010],z,ans,dgr[1010]={1},lst=0,mx,f[1010]; bool fg[1010]={0}; inline bool check(){ int ch = 0; for(int z=1; z<=n; z++){ ch = max(dgr[z],ch); } if(ch <= n/2) return true; return false; } inline int ff(int k){ if(f[k] == k) return k; else return ff(f[k]); } int main(){ for(int i=0; i<1010; i++) dgr[i] = 1, f[i] = i; s(n); for(int i=1; i<=n; i++){ s(m); fg[i] = 1; int cnt = 1; for(int j=1; j<=m; j++){ s(z); a[i][cnt++] = z; } } for(int i=n; i>=1; i--){ for(int j=1; a[i][j]; j++){ if(a[i][j] > i){ int fi = ff(i), fa = ff(a[i][j]); if(fi != fa){ dgr[fi] += dgr[fa]; f[fa] = fi; if(!check()){ printf("%d",i); return 0; } } } } } return 0; }
本文作者:XiaoLe_MC
本文链接:https://www.cnblogs.com/xiaolemc/p/17936449.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步