题目
题目描述
样例输入
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;
}