#并查集#SSL 2342 信息学奥赛一本通 1386 打击犯罪

信息学奥赛一本通链接

题目

求最少打击的团伙数,并且使最大的团伙危险程度不超过n/2。

分析

n n n 1 1 1逆向枚举,每次把点 k k k加入图中,也就是删掉 1 ∼ k − 1 1\sim k-1 1k1,剩余 k ∼ n k\sim n kn,若最大集合点数不超过 n / 2 n/2 n/2,说明这种方案可行, k k k还能更小,一旦不满足,意味着第 k k k个点加入图中就不可行了,所以点 k k k必须得删,所以输出答案。

邻接矩阵代码(0ms 5152k)

#include <cstdio>
#include <cctype>
using namespace std;
int n,a[1001][1001],c[1001],f[1001];
int in(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int getf(int u){return (f[u]==u)?u:f[u]=getf(f[u]);}
int main(){
	n=in();
	for (int i=1;i<=n;i++){
		c[i]=1; f[i]=i; a[i][0]=in();
		for (int j=1;j<=a[i][0];j++)
		a[i][j]=in();
	}
	for (int k=n;k>=1;k--)
	for (int i=1;i<=a[k][0];i++)
	if (a[k][i]>k){//加入
		int x=getf(k),y=getf(a[k][i]);
		if (x!=y){//不同集合
			f[y]=x;
			c[x]+=c[y];//团伙
			if (c[x]>n/2){//超过
				printf("%d",k);
				return 0;
			}
		}
	}
}

邻接表代码(0ms 1276k)

#include <cstdio>
#include <cctype>
using namespace std;
struct node{int y,next;}e[5001];//不可能太多的
int n,m,ls[1001],c[1001],f[1001];
int in(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int getf(int u){return (f[u]==u)?u:f[u]=getf(f[u]);}
int main(){
	n=in(); int t,x,y;
	for (int i=1;i<=n;i++){
		c[i]=1; f[i]=i; t=in();
		for (int j=1;j<=t;j++){//邻接表
		    e[++m].y=in();
			e[m].next=ls[i]; 
			ls[i]=m;
		}
	}
	for (int k=n;k>=1;k--){
	    t=ls[k];
	    while (t){
		if (e[t].y>k){//犯罪团伙
			x=getf(k); y=getf(e[t].y);
			if (x!=y){//不在集合
				f[y]=x;
				c[x]+=c[y];
				if (c[x]>n/2){//超过
					printf("%d",k);
					return 0;
				}
			}
		}
		t=e[t].next;
	    }
	}
}
    原文作者:犯罪团伙问题
    原文地址: https://blog.csdn.net/sugar_free_mint/article/details/79729334
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞