「情報伝達の解題」

先看完題目,別急着看題解了啦

信息傳遞

  • 說白了,就是一道求最小環問題的裸題
  • 自己的信息又傳回來 => 此圖一定有環
  • 當有人從別人口中得知自 己的生日時,遊戲結束 => 最小環問題
  • 傑系一國有向圖
  • 一般有向圖用並查集 & 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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章