P2921 [USACO08DEC]在农场万圣节

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

一道不错的记搜题。

由于每一个人点的出度只能是1,所以我们不难发现:每一条在环上的边只能属于一条环。换句话说:任何一条边顶多属于一个环。这样我们就可以用简单的记搜来实现。

f[i]为从点i开始最多能到达的点的总个数,那么显然,当i在某个环中,f[i]=其他环上的点的f的值;当i不在环中时,f[i]=从i出发最先能到达的环中的点ji的距离+f[j]

具体的实现细节见代码。

Code:

#include<cstdio>
#include<iostream>
using namespace std;

const int MAXN=100020;
int n,nxt[MAXN],fst,dfn[MAXN],huan[MAXN],f[MAXN];

inline int read()
{
	int x=0;
	char ch=getchar();
	while(ch<'0'||'9'<ch)	ch=getchar();
	while('0'<=ch&&ch<='9')
	{
		x=(x <<3)+(x <<1)+(ch-'0');
		ch=getchar();
	}
	return x;
}

void dfs(int x,int tim)
{
	if(nxt[x]==x)	{ f[x]=1; return; }//一定记得判断自环的情况 
	if(f[nxt[x]]>0)  { f[x]=f[nxt[x]]+1; return; }
	dfn[x]=tim;
	if(dfn[nxt[x]]>0)	
	{ 
		huan[x]=1; fst=nxt[x];//huan变量帮助判断当前点是否在环上 
		f[x]=dfn[x]-dfn[nxt[x]]+1; 
		//记录dfs序:当某个点通往一个已被搜到的点nxt[x],说明从nxt[x]到x的路径+单向边w(x,nxt[x])已经构成了一个环。
		//显然这个环的长度=dfn[x]-dfn[nxt[x]]+1;  
		return;
	}
	dfs(nxt[x],tim+1);
	if(huan[nxt[x]]==1)	 
	{ 
		huan[x]=1; f[x]=f[nxt[x]]; 
		if(x==fst)	huan[x]=0;
		return; 
	}
	f[x]=f[nxt[x]]+1;
	return;
}

int main()
{
	n=read();
	for(int i=1;i<=n;i++)	nxt[i]=read();
	for(int i=1;i<=n;i++)
	{
		fst=0;
		if(!dfn[i])	 dfs(i,1);
	}
	for(int i=1;i<=n;i++)	cout<<f[i]<<'\n';
	return 0;
}

猜你喜欢

转载自blog.csdn.net/guapi2333/article/details/83315265