You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
2.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
/**
思路其实就是求最小环。每个点的出度都是1因此构成的图要么是一条链+一个环,要么是几个环,
通过拓扑可以消去链状的部分对环的部分dfs算最小环即可。
*/
const int N = 2e5 + 10;
int n; //n个同学
int ans = 0x3f3f3f3f; //答案,初始值为极大值
vector<int> edge[N]; //邻接表
int ind[N]; //入度数组
queue<int> q; //拓扑排序用的队列
bool st[N]; //是不是已经被排除掉
//拓扑排序[这是一个拓扑排序的模板但里面扩充了本题的st[i]数组标识 ]
void topsort() {
//入度为0的结点入队列
for (int i = 1; i <= n; i++) if (!ind[i]) q.push(i);
//图的广度优先遍历
while (!q.empty()) {
int x = q.front();
q.pop();
//标识非环中结点
st[x] = true;
//遍历每条出边
for (int i = 0; i < edge[x].size(); i++) {
int y = edge[x][i];
ind[y]--;
if (!ind[y]) q.push(y);//在删除掉当前结点带来的入度后是不是入度为0了如果是将点y入队列
}
}
}
/**
功能求图中包含点u的环的长度
参数: u 结点
len 长度
*/
void dfs(int u, int len) {
//标识探测过了
st[u] = true;
//遍历所有u开头的边
for (int y:edge[u]) {
//如果这个点还没有被探测过,那么继续探索
if (!st[y]) dfs(y, ++len);
else { //到这里是发现了环!因为现在在邻接表中只剩下了环,其它的链路都被拓扑排序干掉了,
// 结果还是出现访问过的结点,就肯定是发现环了
ans = min(ans, len); //这是递归的出口.此处和其它的递归不一样啊,递归出口居然在代码区,
// 而不是在一进递归的位置~
return;
}
}
}
int main() {
//创建有向图
cin >> n;
for (int i = 1; i <= n; i++) {
int u;
cin >> u;
//邻接表方式
edge[i].push_back(u);
//入度++
ind[u]++;
}
//拓扑排序
topsort();
//到这里st[i]=false的就应该是环中结点,对环的部分dfs算最小环即可
for (int i = 1; i <= n; i++) if (!st[i]) dfs(i, 1);
cout << ans << endl;
}