【拓扑排序+dfs】P2661 [NOIP 2015 提高组] 信息传递
题目
P2661 [NOIP 2015 提高组] 信息传递
分析
首先根据示例1进行分析,可以得出以下信息传递的关系图:
我们可以发现,2、3、4之间存在一个环,这个环的长度是3,那么意味着在3轮信息传递之后游戏就会结束。
这么分析之后问题就变得简单了,我们只需要通过拓扑排序找到整个关系图中的环,然后dfs环中的某一个结点(拓朴排序后未被标记的结点),然后计算出环的长度,并且要找到最短的那个环长,这样就知道游戏能进行多少轮了。
代码
#include<iostream>
#include<queue>using namespace std;const int N = 2e5 + 10;int ne[N], in[N]; //ne存结点的后继,in存结点的入度
//为什么本题不用vector存i的出边信息,因为本题中每个结点i只有一条出边,入边可以有多条 bool st[N];int cnt;void dfs(int u)
{cnt++;st[u] = true;int v = ne[u];if(!st[v]) dfs(v); //我准备特殊判断ne[x]不能为0的,但是输入格式保证ne[x]不会出现0 }int main()
{int n; cin >> n;for(int i=1;i<=n;i++) //记录关系 {cin >> ne[i];in[ne[i]]++;}//拓扑排序queue<int> q;//把所有入度为0的点加入队列 for(int i=1;i<=n;i++){if(in[i] == 0) {q.push(i);st[i] = true; //也可以不标记,初初始入度为0的点不会被其他点指向,所以它们不会在拓扑排序中被标记,但由于它们不在环中,后续DFS也不会处理它们}} while(q.size()){auto u = q.front(); q.pop();int v = ne[u]; //删掉入度为0的结点的边 in[v]--;if(in[v] == 0) {q.push(v);st[v] = true;} } //最后遍历所有结点,如果有没入队的,就存在环,进行dfs求最短环长 int ret = n;for(int i=1;i<=n;i++){if(!st[i]) {cnt = 0;dfs(i);ret = min(ret,cnt);}} cout << ret << endl;return 0;}