打击犯罪【并查集】
打擊犯罪
題目大意:
有n個人,相互之間有一些關系,從而形成一個圖,現在要從1……n1……n1……n按順序去掉k個人(即去掉1……k1……k1……k),使最大的子圖的點數 <n/2<n/2<n/2,求k的最小值
原題:
題目描述
某個地區有n(n<=1000)個犯罪團伙,當地警方按照他們的危險程度由高到低給他們編號為1-n,他們有些團伙之間有直接聯系,但是任意兩個團伙都可以通過直接或間接的方式聯系,這樣這里就形成了一個龐大的犯罪集團,犯罪集團的危險程度唯一由集團內的犯罪團伙數量確定,而與單個犯罪團伙的危險程度無關(該犯罪集團的危險程度為n)。現在當地警方希望花盡量少的時間(即打擊掉盡量少的團伙),使得龐大的犯罪集團分離成若干個較小的集團,并且他們中最大的一個的危險程度不超過n/2。為達到最好的效果,他們將按順序打擊掉編號1到k的犯罪團伙,請編程求出k的最小值。
如下圖所示,打擊掉1號團伙便能達到目的。
輸入
第一行一個正整數n。
接下來的n行每行有若干個正整數,第一個整數表示該行除第一個外還有多少個整數,若第i行存在正整數k,表示i,k兩個團伙可以直接聯系。
輸出
一個正整數,為k的最小值
輸入樣例
72 2 53 1 3 42 2 42 2 33 1 6 72 5 72 5 6輸出樣例
1解題思路:
因為要按順序,所以我們倒著用并查集加入每一個點,然后看每一個子圖是否符合,當全部符合時繼續,否則就輸出
代碼:
#include<cstdio> #include<cstring> #include<iostream> #define max(a,b) (a)>(b)?(a):(b) #define min(a,b) (a)<(b)?(a):(b) using namespace std; int n,xx,yy,k,a[1005][1005],dad[1005],b[1005]; int find(int dep){return dad[dep]==dep?dep:dad[dep]=find(dad[dep]);}//并查集 void lj(int x,int y) {xx=find(x);yy=find(y);dad[min(xx,yy)]=max(xx,yy);//連接兩個點 } int main() {scanf("%d",&n);for (int i=1;i<=n;++i){scanf("%d",&a[i][0]);for (int j=1;j<=a[i][0];++j)scanf("%d",&a[i][j]);}for (int i=1;i<=n;++i)dad[i]=i;int i=n+1;while (!k){i--;for (int j=1;j<=a[i][0];++j)if (a[i][j]>=i) lj(i,a[i][j]);//插入點memset(b,0,sizeof(b));for (int j=i;j<=n;++j)b[find(j)]++;//累加for (int j=i;j<=n;++j){if (b[j]>n/2)//判斷{k=1;//不符合break;}}}printf("%d",i); }總結
- 上一篇: 您的电脑需要多少内存您的电脑需要多少内存
- 下一篇: 糊涂的教授【拓扑排序】