LG-P2835 刻录光盘

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xu0_zy/article/details/83715268

题目链接:https://www.luogu.org/problemnew/show/P2835

这题最容易让人误以为是并查集。实际上并没有必要用并查集(并查集好像是有反例的)。
部分代码hack数据:https://share.weiyun.com/5hzYaLG

最大的问题就在于可能有环会出现,这会导致很多问题。所以我们要做的就是先把环缩成点。

做完之后,我们发现,只要一个点有父节点,那么就没必要单独发给他,所以统计入度为零的点即可。

费罗伊德缩环

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=205,maxm=maxn*maxn;
int n,ans,f[maxn][maxn],fa[maxn];
int rad()
{
	int ret;scanf("%d",&ret);return ret;//为了应对 洛谷第6个点
//	int ret=0,f=1;char ch=getchar();
//	while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
//	while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
//	return ret*f;
}
int main()
{
	n=rad();
	for (int i=1;i<=n;++i) for (int x=rad();x;x=rad()) f[i][x]=1;
	for (int i=1;i<=n;++i) fa[i]=i;
	for (int k=1;k<=n;++k)
	for (int i=1;i<=n;++i)
	for (int j=1;j<=n;++j)
	  if (i!=j&&j!=k&&k!=i) f[i][j]|=f[i][k]&f[k][j];
	for (int i=1;i<=n;++i)
	 for (int j=1;j<=n;++j)
	   if (i!=j&&f[i][j]) fa[j]=fa[i];
	for (int i=1;i<=n;++i) ans+=fa[i]==i;
	printf("%d",ans);return 0;
}

塔尖缩环

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=205,maxm=maxn*maxn;
int n,ans,lnk[maxn],tot,nxt[maxm],son[maxm],fa[maxn];
int dfn[maxn],low[maxn],vis[maxn],st[maxn],tp,tim,f[maxn],bel[maxn],cnt;
int rad()
{
	int ret;scanf("%d",&ret);return ret;
//	int ret=0,f=1;char ch=getchar();
//	while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
//	while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
//	return ret*f;
}
void add(int x,int y){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;}
void tarjan(int x)
{
	low[x]=dfn[x]=++tim;
	vis[st[++tp]=x]=1;
	for (int i=lnk[x],y;i;i=nxt[i]) if (!dfn[y=son[i]])
	{
		tarjan(y);
		low[x]=min(low[x],low[y]);
	}else if (vis[y]) low[x]=min(low[x],dfn[y]);
	if (low[x]==dfn[x]){
		++cnt;
		do{
			bel[st[tp]]=cnt;
			vis[st[tp--]]=0;
		}while(st[tp+1]!=x&&tp>0);
	}
}
int main()
{
	n=rad();
	for (int i=1;i<=n;++i) for (int x=rad();x;x=rad()) add(i,x);
	for (int i=1;i<=n;++i) if (!dfn[i]) tarjan(i);
	for (int i=1;i<=n;++i)
	{
		for (int j=lnk[i];j;j=nxt[j])
		{
			if (bel[son[j]]==bel[i]) continue;
			f[bel[son[j]]]=1;
		}
	}
	ans=0;
	for (int i=1;i<=cnt;++i)
	  if (!f[i]) ++ans;
	printf("%d",ans);return 0;
}

猜你喜欢

转载自blog.csdn.net/xu0_zy/article/details/83715268