动规(20)-并查集基础题——打击犯罪

【问题描述】

   某个地区有n(n<=1000)个犯罪团伙,当地警方按照他们的危险程度由高到低给他们编号为1-n,他们有些团伙之间有直接联系,但是任意两个团伙都可以通过直接或间接的方式联系,这样这里就形成了一个庞大的犯罪集团,犯罪集团的危险程度唯一由集团内的犯罪团伙数量确定,而与单个犯罪团伙的危险程度无关(该犯罪集团的危险程度为n)。现在当地警方希望花尽量少的时间(即打击掉尽量少的团伙),使得庞大的犯罪集团分离成若干个较小的集团,并且他们中最大的一个的危险程度不超过n/2。为达到最好的效果,他们将按顺序打击掉编号1k的犯罪团伙,请编程求出k的最小值。

【输入格式】black.in

  第一行一个正整数n。接下来的n行每行有若干个正整数,第一个整数表示该行除第一个外还有多少个整数,若第i行存在正整数k,表示ik两个团伙可以直接联系。

【输出格式】black.out

一个正整数,为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

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n, maxt, i, j, r1, r2, q, f, t;
int head[1001], s[1001], father[1001];
struct node
{
    int data, nex;
} p[100000];
int find(int x)
{
    return father[x] == x ? x : father[x] = find(father[x]);
}
void lian(int x, int y)
{
    p[++q].nex = head[x];
    p[q].data = y;
    head[x] = q;
}
int main()
{
    cin >> n;
    maxt = n / 2;
    for (i = 1; i <= n; i++)
    {
        cin >> t;
        for (j = 1; j <= t; j++)
        {
            cin >> f, lian(i, f);
        }
    }
    for (i = 1; i <= n; i++)
    {
        father[i] = i;
        s[i] = 1;
    }
    for (i = n; i >= 1; i--)
        for (j = head[i]; j; j = p[j].nex)
            if (p[j].data > i)
            {
                r1 = find(i);
                r2 = find(p[j].data);
                if (r1 != r2) //必须判断,否则"加重 ”
                {
                    father[r2] = r1;
                    s[r1] = s[r1] + s[r2];
                }
                if (s[r1] > maxt)
                {
                    cout << i;
                    return 0;
                }
            }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hdq1745/article/details/126812636