acw - 4626. 最小移动距离(基环树,gcd)

题意
平面上有 n 个点,编号为 1∼n。

对于每个点 i ( 1 ≤ i ≤ n ) i(1≤i≤n) i1in,都存在一条从点 i 到点 a i ( 1 ≤ a i ≤ n , a i a_i(1≤a_i≤n,a_i ai1ainai 可以等于 i)的有向边。所有边的长度均为 1。

请你判断是否存在一个最小移动距离 t ( t ≥ 1 ) t(t≥1) tt1,使得:

  • 我们规定,如果从点 u u u 出发,移动 t t t 单位长度距离后,到达点 v v v,就称点 v v v 是点 u u u 的目标点。注意,一个点的目标点也可能是它自己。
  • 对于图中的每个点 x,如果点 y 是点 x 的目标点,则点 x 也必须是点 y 的目标点。

如果存在这样的 t,请你输出 t 的最小可能值,否则请你输出 -1。

1 ≤ n ≤ 100 , 1 ≤ a i ≤ n 1≤n≤100,1≤a_i≤n 1n1001ain

思路
一开始是这样想的:
没考虑到 t 可能因为在环中重复跑而会不断增大,只觉得 t 最大到 n,所以就用 dp 跑了一遍,处理出来 f[i, j, k] 表示从 i 点开始,走 j 步能否到达 k 点。后面几个点没过去。

正解是这样的:
需要注意到图的样式,对于每个点有且只有一个出边,一共 n 个点 n 个点,那么说明这个图是基环树或者不连通的基环树森林。
请添加图片描述

那么如果存在一个树挂到环上的情况(如上图左边的基环树),树上的点一旦进入环中就不可能再出来,所以树上的点 x 走任何步到达一个目标点,目标点都不可能再走到 x,无解。

那么有解的情况就是图中只存在若干个环,并且在基环树森林中,这些环一定都是各不相交的。

  • 如果环是奇数环,那么对于环中的点来说,如果要满足走若干步到达的点能够到达自己,那么只能是走遍环上的所有点走到自己,目标点就是自己,走过的步数是环的长度。
  • 如果环是偶数环,对于环中的点,要满足走若干步到达的点也能够到达自己,那么步数最小值可以是环的长度除2,走到中间的节点,中间的节点也能走回自己。

为了让图中所有的节点都能满足走 t 步到达的节点都能到达自己,那么 t 就应该是所有奇数环长度与所有偶数环长度/2 的最小公倍数。

因为环与环之间不相交,所以可以直接DFS求出图中所有环,也可以用并查集维护。

#include<bits/stdc++.h>
using namespace std;

#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define int long long

const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N], f[N];
vector<int> e[N];
int len, ans = 1;
int ru[N];

void dfs(int x)
{
	len ++;
	for(int tx : e[x])
	{
		if(f[tx])
		{
			int t = len;
			if(len % 2 == 0) t = len / 2;
			ans = ans * t / __gcd(ans, t);
		}
		else
		{
			f[tx] = 1;
			dfs(tx);
		}
	}
	len --;
}

signed main(){
	Ios;
	cin >> n;
	for(int i=1;i<=n;i++)
	{
		int x; cin >> x;
		e[i].push_back(x);
		ru[x] ++;
	}
	
	int flag = 0;
	for(int i=1;i<=n;i++) if(ru[i] != 1) flag = 1;
	if(flag){
		cout << -1;
		return 0;
	}
	
	for(int i=1;i<=n;i++)
	{
		if(!f[i]) f[i] = 1, len = 0, dfs(i);
	}
	cout << ans;
	
	return 0;
}

要时刻牢记,n 个点 n-1 条边的连通图是一棵树,n 个点 n 条边的连通图是基环树。其实就是一棵树加了一个边构成了一个环,然后可以看作环上挂了若干个树。

而 n 个点,每个点都有且只有一个出度,那么是一个基环树,并且环上挂的树都指向环上节点。


要额外留意由输入格式所传递的信息,就比如说在这个题中,根本没说这个图是怎么样的,根本没说图里有 n 条边,没说每个点都有且只有一个出度,这些条件都是由输入格式得到的,有了这些条件才知道这是个基环树,是个什么样的图,然后才能继续往下做。如果不关注图的输入格式,把它当成一般图了,那到最后肯定没有思路。
之前这样的情况遇到过几次了,暑假多校遇到过,前几天的模拟赛又遇到了,想了好长时间之后,又看了一遍题,才发现图里只有 n-1 条边,这是个树!!

所以以后碰见图论题,先看这个图哪里有特殊的地方!防止漏掉这个信息!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值