第三部分 數據結構 -- 第四章 圖論算法1386:打擊犯罪(black)

1386:打擊犯罪(black)

時間限制: 1000 ms 內存限制: 65536 KB
提交數: 2477 通過數: 1355
【題目描述】
某個地區有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
【提示】
【提示】

輸出1(打擊掉犯罪團伙)
在這裏插入圖片描述


思路:如果從1~n枚舉去掉1-k的點,判斷每次統計最大集合點數是否不超過n/2,則爲答案,每次枚舉都要重置並查集,考慮逆向思考,n ~ 1枚舉,每次把K加入圖中,也就是刪除1 ~ K-1,剩餘k ~ n,若最大集合點不超過N/2這個方案可行還可能更小,一旦不滿足就是不能再加K,即K 要刪掉,就輸出答案。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1500;
int p[N];
int c[N];
int a[N][N];
int findth(int x)//查找x所在集合的根 
{
    if (x == p[x]) return x;
    return p[x] = findth(p[x]);
}
int main()
{
    int n;
    scanf("%d", &n);

    for (int i = 1;i <= n;i++) {//初始化,把每個點看作一個集合,其根爲它本身 個數爲1 
        p[i] = i;
        c[i] = 1;//個數爲1  
    }
    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 = n;i >= 1;i--) {//從n 到1逆序枚舉每次把點K 加入圖中 
        for (int j = 1;j <= a[i][0];j++) {//把與其相連的點併到K所在集合裏 
            if (a[i][j] > i) {         //如果這個點現在是在圖裏,即大於K 才能進行操作 
                int xx = findth(i);
                int yy = findth(a[i][j]);
                if (xx != yy) {
                    p[yy] = xx; //將這個點併到K所在集合中 
                    c[xx] += c[yy];//累加集合的元素個數 
                    if (c[i] > (n >> 1)) {//若集合點數超過n/2,則點K 不能加入圖中,必須刪,k也不能更小 
                        printf("%d\n", i);//輸出答案 
                        return 0;
                    }
                }
                
            }
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章