P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm(有环图的搜索)

52 篇文章 3 订阅
32 篇文章 1 订阅

P2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm
题目描述
Every year in Wisconsin the cows celebrate the USA autumn holiday of Halloween by dressing up in costumes and collecting candy that Farmer John leaves in the N (1 <= N <= 100,000) stalls conveniently numbered 1…N.

Because the barn is not so large, FJ makes sure the cows extend their fun by specifying a traversal route the cows must follow. To implement this scheme for traveling back and forth through the barn, FJ has posted a ‘next stall number’ next_i (1 <= next_i <= N) on stall i that tells the cows which stall to visit next; the cows thus might travel the length of the barn many times in order to collect their candy.

题意翻译
题目描述
每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在N(1<=N<=100,000)个牛棚隔间中留下的糖果,以此来庆祝美国秋天的万圣节。

由于牛棚不太大,FJ通过指定奶牛必须遵循的穿越路线来确保奶牛的乐趣。为了实现这个让奶牛在牛棚里来回穿梭的方案,FJ在第i号隔间上张贴了一个“下一个隔间”Next_i(1<=Next_i<=N),告诉奶牛要去的下一个隔间;这样,为了收集它们的糖果,奶牛就会在牛棚里来回穿梭了。

FJ命令奶牛i应该从i号隔间开始收集糖果。如果一只奶牛回到某一个她已经去过的隔间,她就会停止收集糖果。

在被迫停止收集糖果之前,计算一下每头奶牛要前往的隔间数(包含起点)。

输入格式
第1行 整数n。

第2行到n+1行 每行包含一个整数 next_i 。

输出格式
n行,第i行包含一个整数,表示第i只奶牛要前往的隔间数。

样例解释
有4个隔间

隔间1要求牛到隔间1

隔间2要求牛到隔间3

隔间3要求牛到隔间2

隔间4要求牛到隔间3

牛1,从1号隔间出发,总共访问1个隔间;

牛2,从2号隔间出发,然后到三号隔间,然后到2号隔间,终止,总共访问2个隔间;

牛3,从3号隔间出发,然后到2号隔间,然后到3号隔间,终止,总共访问2个隔间;

牛4,从4号隔间出发,然后到3号隔间,然后到2号隔间,然后到3号隔间,终止,总共访问3个隔间。

翻译提供者:吃葡萄吐糖

输入输出样例
输入 #1

4 
1 
3 
2 
3 

输出 #1

1 
2 
2 
3 

刚开始看很容易,不就是搜索吗?写起来各种挂。。。看题解,带环的图?好像也是,我怎么没想到,tarjan就写过一次,硬着头皮写了。这题挺好的,加深了我对图和tarjan算法的理解,虽然是入门题我也看了间接着好几天TAT,原来图没我想的那么简单。
每个通过其他点不能到自己点的点就是一个强连通分量,就像一条链连着一条环,这条链上的每个点都是一个强连通分量,在tarjan算法里面也会被记录到。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
const int N=100005;
const int inf=0x3f3f3f3f;
int to[N],col[N],dfn[N],low[N],stack[N],ans[N],sum[N];
int top,co=0,dep;
void tarjan(int x){
	dfn[x]=low[x]=++dep;
	stack[++top]=x;
	if(!dfn[to[x]]){
		tarjan(to[x]);
		low[x]=min(low[x],low[to[x]]);
	}
	else if(!col[to[x]]){
		low[x]=min(low[x],dfn[to[x]]);
	}
	if(low[x]==dfn[x]){
		co++;
		int t;
		do{
			t=stack[top--];
			col[t]=co;//记录第几个环 
			sum[co]++;//环的规模+1 
		}while(t!=x);
	}
}
int dfs(int x,int t){//x是当前点,t是下上一个点 
	if(col[x]==col[t]) return 0;
	if(ans[x]) return ans[x];
	int s=sum[col[x]];
	return ans[x]=s+dfs(to[x],x);
}
int main()
{
	int n,i,j,m,k,x,y;
	scanf("%d",&n); 	
	for(i=1;i<=n;i++)
		scanf("%d",&to[i]);      
	for(i=1;i<=n;i++)
		if(!dfn[i])
			tarjan(i);
	for(i=1;i<=n;i++){
		printf("%d\n",dfs(i,0));
	}
	
	return 0;
}

上面的是看的题解写的,理解了之后把我的改一下就对了,我的更好理解一些。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
const int N=100005;
const int inf=0x3f3f3f3f;
int to[N],v[N],dfn[N],low[N],stack[N],ans[N];
int top,dep,t;
void tarjan(int x){
	dfn[x]=low[x]=++dep;
	stack[++top]=x;
	v[x]=1;
	if(!dfn[to[x]]){
		tarjan(to[x]);
		low[x]=min(low[x],low[to[x]]);
	}
	else if(v[to[x]]){
		low[x]=min(low[x],dfn[to[x]]);
	}
	if(low[x]==dfn[x]){
		int c=1;
		for(int i=top;i>=1;i--){
			if(stack[i]==x) break;
			c++;
		}
		do{
			ans[stack[top]]=c;
			v[stack[top]]=0;
			top--;
		}while(x!=stack[top+1]);
	}
}
int dfs(int x){
	if(to[x]==x||ans[x]!=1) return ans[x];
	else {
		return ans[x]=ans[x]+dfs(to[x]);
	}	
	
}
int main()
{
	int n,i,j,m,k,x,y;
	scanf("%d",&n);
 // 	freopen("in.txt","r",stdin);freopen("put.txt","w",stdout);
  	
	for(i=1;i<=n;i++)
		scanf("%d",&to[i]);      
	for(i=1;i<=n;i++)
		if(!dfn[i])
			tarjan(i);
	for(i=1;i<=n;i++){
		printf("%d\n",dfs(i));
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值