P2921 在农场万圣节(非递归的类似于记忆化搜索的巧妙方法||记忆化搜索||tarjan)

1、

//秉持着必然进入一个环的思想
#include<bits/stdc++.h>
using namespace std;
const int N=100009;
int color[N];//记录此节点的颜色(也就是是哪个节点发出的路径经过了这个节点)
int circle[N];//记录环大小
int dfn[N];//记录此节点的时间戳
int indfn[N];//记录入环时间戳
int nxt[N];//记录题目所给的下一个隔间是哪儿
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>nxt[i];
    }
    for(int cow=1;cow<=n;cow++)//循环每一只牛
    {
        for(int i=cow,cnt=0;;i=nxt[i],cnt++)
        {
            if(!color[i])//如果这个节点还没有走过
            {
                color[i]=cow;//记录节点颜色
                dfn[i]=cnt;//记录时间戳
            }
            else if(color[i]==cow)//如果本来就位于环内或者通过一条没人走过的路进入环内
            {
                circle[cow]=cnt-dfn[i];//环大小为此时时间减去入环时间
                indfn[cow]=dfn[i];//入环时间戳就是该店的时间戳(因为我们再次回到这个点的时候我们并没有对这个点的时间戳进行改动)
                cout<<cnt<<endl;
                break;
            }
            else//如果这个点曾经是另一条路径走过的
            {
                circle[cow]=circle[color[i]];//环的大小复制过来
                indfn[cow]=cnt+max(0,indfn[color[i]]-dfn[i]);//入环时间戳
                                                            //如果cow这个点在环内,那么cnt直接就是入环时间戳(max内另一项小于等于0)
                                                            //如果不在环内,算下距离
                cout<<indfn[cow]+circle[cow]<<endl;//入环时间戳加上环的大小就是答案
                break;
            }
        }
    }
    return 0;
}

 

posted on 2020-02-09 21:32  greenofyu  阅读(255)  评论(0编辑  收藏  举报