题目链接:图
时间限制: C/C++ 1秒,其他语言2秒
空间限制: C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
现在有一个N个点的有向图,每个点仅有一条出边
你需要求出图中最长的简单路径包含点的数量
(1≤N≤1,000,000)
输入描述:
第一行一个数字N
接下来N行,每行一个正整数,第i+1行的数字表示第i个点出边终点的编号
(点从1开始标号)
输出描述:
一行一个数字,最长的简单路径的长度
示例1
输入
复制
3
2
3
2
输出
3
解题思路
这一题也就是在有向图上遭到最长的一跳路径,因为每个节点的出度只有一条,那么我们也就可以肯定,这一条最长的单元路径的长度也就是咋调路上的点数。这里我用tarjon缩点,然后进行跑拓扑图进行的。跑到最后的一个节点的时候一定要记得加上这个节点的联通分量的个数然后减一这是为全部是一个环不知道为傻缩完点之后根据颜色构造新图,然后跑BFS,不知道为啥T了, 希望大佬们指点下!!!
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fast ios::sync_with_stdio(0)
const int mx=1000010;
int dfn[mx],low[mx];//tarjon模板数组
int a[mx],du[mx];//存图和记录入度
int color[mx],color_num[mx];//记录
vector<int>ve[mx];
int cnt,sum,n,m;
bool vis[mx];
int dis[mx];
stack<int>st;
void tarjon(int x)
{
dfn[x]=low[x]=++cnt;
st.push(x);
vis[x]=1;
int i=a[x];
if(!dfn[i]){//如果dfn 为零说明还没遍历过就遍历这个点
tarjon(i);
low[x]=min(low[i],low[x]);//更新low的值
}
else if(vis[i])//如果遍历过了,切在栈里面就直接更新 low 的值就行了
{
low[x]=min(low[x],dfn[i]);
}
int k;
if(low[x]==dfn[x])//如果 low 等于 dfn 说明这个点为一个联通分量
{
sum++;//每一个联通分量为一种颜色
do
{
k=st.top();//将栈的最顶端元素取出来
st.pop();
vis[k]=0;//恢复标记
color[k]=sum; //点k属于颜色 sum
color_num[sum]++;//颜色 sum 的节点数加一
}while(k!=x);//遍历该联通分量的元素被遍历完;
}
}
int main()
{
fast;
cin>>n;
for(register int i=1;i<=n;i++) cin>>a[i],du[a[i]]++;
for(register int i=1;i<=n;i++)
{
if(!dfn[i]) tarjon(i);
}
if(sum==1)
{
cout<<color_num[sum]<<"\n";
return 0;
}
queue<int>q;
for(register int i=1;i<=n;i++)
{
dis[i]=1;
if(!du[i]) q.push(i);
}
while(!q.empty())//常规的跑拓扑图从入度为 0的节点开始
{
int u=q.front();q.pop();
int v=a[u];
dis[v]=dis[u]+1;//更新路径的长度
if(--du[v]==0) q.push(v);
}
int ans=0;
for(int i=1;i<=n;i++){//如果结束,加上最后那个节点的联通的所有节点
ans=max(ans,dis[i]+color_num[color[i]]-1);
}
cout<<ans<<"\n";
return 0;
}
来源:CSDN
作者:浅眠流转
链接:https://blog.csdn.net/qq_43750980/article/details/104355446