一道藏得很深的并查集的题,
看到算法标签才反应过来是并查集。
写的时候编译器还莫名的抽风了。。。
题目描述
有一个由 n 个元素组成的序列 a1,a2,…,an;最初,序列中的每个元素满足 ai=i。
对于每次操作,你可以交换序列中第 i个元素和第 j 个元素当且仅当满足 |i−j|=di。
题目给出序列 b1,b2,…,bn和 d1,d2,…,dn,询问是否可以通过若干次交换,使得序列 a 和序列 b 完全相同。
输入格式
第 1 行一个正整数 n,含义如上。
第 2行 n 个正整数表示 b1,b2,…,bn。
第 3 行 n 个正整数表示 d1,d2,…,dn。
输出格式
若能,输出 YES
;否则输出 NO
。
输入 #1
7
4 2 5 1 3 7 6
4 6 6 1 6 6 1
输出 #1
YES
输入 #2
7
4 3 5 1 2 7 6
4 6 6 1 6 6 1
输出 #2
NO
数据范围
1≤n,di≤100。保证序列 b 中元素不重复。
补充说明
原题:CF28B pSort | 洛谷
思路就是遍历一遍d数组,对于每一个i和i±[i]进行合并操作
最后在遍历一遍目标数组,一旦发现目标数组b中的b[i]与i不是同一个祖先(也就是不联通)就一定是NO。
#include<iostream>
#include<cstdio>
using namespace std;
int arr[105];
int b[105];
int d[105];
int find(int x)
{
while (x != arr[x])
{
x = arr[x];
}
return x;
}
void merge(int x, int y)
{
int lx = find(x);
int ly = find(y);
if (lx != ly)
{
arr[lx] = ly;
}
}
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
arr[i] = i;
}
for (int i = 1; i <= n; i++)
{
cin >> b[i];
}
for (int i = 1; i <= n; i++)
{
cin >> d[i];
}
for (int i = 1; i <= n; i++)
{
if (i - d[i] >= 1)
{
merge(i - d[i], i);
}
if (i + d[i] <= n)
{
merge(i + d[i], i);
}
}
for (int i = 1; i <= n; i++)
{
int j = b[i];
if (find(j) != find(i))
{
puts("NO");
return 0;
}
}
puts("YES");
return 0;
}
2022/5/15