打击犯罪(题解)

题目

题目描述

样例输入

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

关于本题

  • 这个题反着想会很简单,也就是复活犯罪,但是这个反着的思路不好想到(比如我就没想到)。
  • 看其他blog基本上都是反着来的,确实复杂度小不少,但是别人写过的我就不写了,我就给出正着来的解法。
  • 思路很简单,就是不断的删去一个父亲节点,这样就相当于打击了这个节点,当然每次去除都需要重新建立节点之间的关系(记得初始化),下面给出代码。
#include<bits/stdc++.h>
using namespace std;

const int maxn=1010;

int n,m,ans;
int fa[maxn],group[maxn][maxn],risk[maxn];
//group[i][j]记录以i为父亲节点的团伙j,为了每次重新建立关系

int getfa(int x)
{
	if(x==fa[x])return fa[x];
	return fa[x]=getfa(fa[x]);
}

void merge(int x,int y)
{
	if(getfa(x)!=getfa(y))fa[getfa(y)]=getfa(x);
}

int main()
{
	std::ios::sync_with_stdio(false);
	cin >>n;
	for(int j=1;j<=n;j++)
	{
		cin>>m;
		group[j][0]=m;
		for(int i=1;i<=m;i++)
		{
			cin >>group[j][i];
		}
	}
    //每次删去i节点
	for(int i=1;i<n;i++)
	{
		memset(risk,0,sizeof(risk));
		for(int j=1;j<=n;j++)
		{
			fa[j]=j;
		}
		ans=0;
		for(int j=i+1;j<=n;j++)
		{
			for(int k=1;k<=group[j][0];k++)
			{
				if(group[j][k]>j)merge(j,group[j][k]);
                //小于当前节点的节点已经被删去了,所以不参与建立新的关系
			}
		}
        //如果两个节点的根节点相同,那么着两个节点属于一个团伙,所以求危险程度只需要便利根节点
		for(int j=i+1;j<=n;j++)
		{
			risk[getfa(j)]++;
		}
		for(int j=i+1;j<=n;j++)
		{
			ans=max(ans,risk[j]);
		}
		if(ans<=n/2)
		{
			cout <<i;
			return 0;
		}
	}
	
	return 0;
}
posted @ 2024-02-29 12:06  藦兲轮の约顁  阅读(45)  评论(0编辑  收藏  举报