题意
平面上有 n 个点,编号为 1∼n。
对于每个点 i ( 1 ≤ i ≤ n ) i(1≤i≤n) i(1≤i≤n),都存在一条从点 i 到点 a i ( 1 ≤ a i ≤ n , a i a_i(1≤a_i≤n,a_i ai(1≤ai≤n,ai 可以等于 i)的有向边。所有边的长度均为 1。
请你判断是否存在一个最小移动距离 t ( t ≥ 1 ) t(t≥1) t(t≥1),使得:
- 我们规定,如果从点 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 1≤n≤100,1≤ai≤n
思路
一开始是这样想的:
没考虑到 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 条边,这是个树!!
所以以后碰见图论题,先看这个图哪里有特殊的地方!防止漏掉这个信息!