「情報伝達の解题」

先 看 完 题 目 , 别 急 着 看 题 解 了 啦 先看完题目,别急着看题解了啦

信息传递

  • 说白了,就是一道求最小环问题的裸题
  • 自己的信息又传回来 => 此图一定有环
  • 当有人从别人口中得知自 己的生日时,游戏结束 => 最小环问题
  • 杰系一国有向图
  • 一般有向图用并查集 & 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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值