信息傳遞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;
}

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