信息传递dfs

有 nn 个同学( 编号为 11 到 nn)正在玩一个信息传递的游戏。

在游戏里每人都有一个固定的信息传递对象,其中,编号为 nn 的同学的信息传递对象是编号为 T_iTi的同学。游戏开始时,每人都只知道自己的生日。之后每一轮中,所有人会同时将自己当前所知的生日信息告诉各自的信息传递对象( 注意:可能有人可以从若干人那里获取信息,但是每人只会把信息告诉一个人,即自己的信息传递对象)。 当有人从别人口中得知自己的生日时, 游戏结束。 请问该游戏一共可以进行几轮?

输入格式

输入共 22 行。

第 11 行包含 11 个正整数 n(2 \le n \le 200000)n(2n200000),表示 nn 个人。

第 22 行包含 nn 个用空格隔开的正整数 T_1, T_2, \cdots, T_nT1,T2,,Tn,其中第 ii 个整数 T_iTi 表示编号为 ii 的同学的信息传递对象是编号为 T_iTi 的同学, T_i \le nTin 且 T_i \ne iTii。数据保证游戏一定会结束。

对于50%的数据 n \le 2000n2000

输出格式

输出共 11 行,包含 11 个整数,表示游戏一共可以进行多少轮。

样例输入

5
2 4 2 3 1

样例输出

3
//version1
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 200050;
int nex[maxn];
int visited[maxn];
int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    for(int i = 0; i < n;)
        cin >> nex[++i];
    
    int step = 1;
    int ans = 0x3f3f3f3f;
    for(int i = 0; i < n;){
        int cur = ++i;// 当前节点没有被访问过
        int start = step;
        while(visited[cur] == 0){
            visited[cur] = step++;// 访问当前节点
            if(visited[nex[cur]] == 0){// 若下一个节点也没被访问过
                ;
            }
            else{// 若下一个节点已经被访问过了
                if(visited[nex[cur]] < start)// 若是这个节点不是是本次访问访问的, 就什么也不做
                    ;
                else{// 若是本次访问的, 就计算距离
                    ans = min(ans, visited[cur] - visited[nex[cur]] + 1);
                }
            }
            cur = nex[cur];// 不管怎么样, 都要指向下一个节点
        }
    }
    cout << ans << endl;
    return 0;
}

/*这是在version1提交过之后, 简单修改version1得到的, 形式比较紧凑
起初看到这道题的时候, 只想到了用一个set之类的容器, 去维护每个人知道的生日, 
但是想想数据范围和具体操作就感觉不行;
晚上睡觉没睡着, 突然想到了一点思路, 每个人只会告诉其他一个人,
把这个抽象为边后, 就能得到一个图, 这道题就是要求这个图最小的环有几个元素
样例: 5 -> 1 -> 3
          ^    |
          |- 4 <-
把样例抽象, 大约是这样
后来发现, 这是NOI的一道题, 别人的思路是dfs,
我后来想了想, 我的代码也是dfs, 思路还是不清晰.
*/
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 200050;
int nex[maxn];
int visited[maxn];
int main()
{
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    for(int i = 0; i < n;)
        cin >> nex[++i];
    
    int step = 1;
    int ans = 0x3f3f3f3f;
    for(int i = 0; i < n;){
        int cur = ++i;// 当前节点没有被访问过
        int start = step;
        while(visited[cur] == 0){
            visited[cur] = step++;// 访问当前节点
            if(visited[nex[cur]] != 0){// 如果next指向的节点已经被访问过
                if(visited[nex[cur]] >= start){// 如果是这次访问的, 就说明, 形成环路了
                    ans = min(ans, visited[cur] - visited[nex[cur]] + 1);
                }
            }
            cur = nex[cur];// 不过怎样, 都要把cur = next[cur]
        }
    }
    cout << ans << endl;
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章