先看完題目,別急着看題解了啦
信息傳遞
- 說白了,就是一道求最小環問題的裸題
- 自己的信息又傳回來 => 此圖一定有環
- 當有人從別人口中得知自 己的生日時,遊戲結束 => 最小環問題
- 傑系一國有向圖
- 一般有向圖用並查集 & dfs可以求解
好,我們先來看一下並查集怎麼做
並查集其實就是找自己的大哥,那怎麼用它找環呢?其實就是在找刀哥的過程中,找回自己,就形成了環,那最小環有怎麼求呢?在枚舉時,用一個cnt來記錄每個點回到自己所需要的路程,這就是最後的答案了,完美 !
來來來,話不多說,上代碼:
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N = 200000 + 1;
int n, t[N], ans = ~0u >> 1;
inline int Find(int k, int &cnt){
cnt++;//記錄環長
return t[k] == k ? k : (Find(t[k], cnt));
// if (t[k] == k) return k;
// else return t[k] = Find(t[k], cnt);
}
signed main(){
scanf("%d", &n);
for(re int i = 1; i <= n; i++) t[i] = i;//初始化
for(re int i = 1; i <= n; i++){
int cnt = 0, num;
scanf("%d", &num);
if(Find(num, cnt) == i) ans = min(ans, cnt);
else t[i] = num;
}
printf("%d", ans);
return 0;
}
好,我們再來看看第二種做法dfs
首先枚舉,然後在枚舉的過程中用一個vis記錄該點是否訪問過,以防進入一個死遞歸, 在用l數組記錄枚舉的該點到每一點的路程,環的大小就可以用總的路程減去起點第一次到該點時的路程,這就是我們要求的環的大小,最後在取個min值,就好了!
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N = 200000 + 1;
int t[N], n, l[N] = {0}, minn = ~0u >> 1;
bool back[N] = {0}, vis[N] = {0};
//back[i]: 是否會回到原點,形成環
//vis[i]: 是否訪問過的點
void dfs(int node, int cnt){
if(vis[node]) return;
if(back[node]) minn = min(minn, cnt - l[node]);
else{
back[node] = 1;
l[node] = cnt;
dfs(t[node], cnt + 1);
vis[node] = 1;
}
}
signed main(){
scanf("%d", &n);
for(re int i = 1; i <= n; i++) scanf("%d", &t[i]);
for(re int i = 1; i <= n; i++) dfs(i, 0);
printf("%d", minn);
fclose(stdin), fclose(stdout);
}