题目链接:https://www.luogu.org/problemnew/show/P2661
这题仔细分析一下是有向图最短路径问题,然后看了一眼数据量,Dijkstra等算法不能过。看了大佬的题解,发现这题能用拓扑排序或并查集解决。
1.拓扑排序
这题由于每一个人只能传递给一个人,出度为1.先把出度为0的删去,把周围顶点入度-1,若入度为0,放入队列。。。
拓扑排序中的点删去,剩下的点就是环。因为出度只能为1,每个点只能在一个环中。DFS遍历即可。
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
struct Node{
int t;
}G[200010];
int indegree[200010]; //入度数组
int del[200010]; //记录被删除的节点
void Topsort(int n) //拓扑排序
{
int v;
queue <int> q;
for (int i=1;i<=n;i++)
{
if (indegree[i]==0)
q.push(i);
}
while(!q.empty())
{
v=q.front();
q.pop();
del[v]=1;
indegree[G[v].t]--;
if (indegree[G[v].t]==0)
q.push(G[v].t);
}
}
int dfs(int t,int step) //DFS求环的步数
{
if (del[t]==1)
return step;
del[t]=1; //每经过一个点,删了它。
step++;
return dfs(G[t].t,step);
}
int main()
{
int n,x,y,step=1000000;
scanf ("%d",&n);
for (int i=1;i<=n;i++)
{
scanf ("%d",&x);
G[i].t=x;
indegree[x]++;
}
Topsort(n);
for (int i=1;i<=n;i++)
{
if (del[i]==0)
{
step=min(dfs(i,0),step);
}
}
printf ("%d\n",step);
}