Codeforces 28B – pSort
题目
One day n cells of some array decided to play the following game. Initially each cell contains a number which is equal to it’s ordinal number (starting from 1). Also each cell determined it’s favourite number. On it’s move i-th cell can exchange it’s value with the value of some other j-th cell, if |i-j|=d{i}, where d{i} is a favourite number of i-th cell. Cells make moves in any order, the number of moves is unlimited.
The favourite number of each cell will be given to you. You will also be given a permutation of numbers from 1 to n. You are to determine whether the game could move to this state.
输入格式
The first line contains positive integer n (1<=n<=100) — the number of cells in the array. The second line contains n distinct integers from 1 to n — permutation. The last line contains n integers from 1 to n — favourite numbers of the cells.
输出格式
If the given state is reachable in the described game, output YES, otherwise NO.
该题目的目的为判断某数列在经过多次交换后能否达到目标数列,数列中元素i只能与其相距的d{i}的元素进行交换
即将数列中元素能够交换的元素放置同一集合中(可以为一次交换的元素,也可以为多次交换的元素),因此我们可以联想到 并查集
除了并查集,还可以使用DFS,先将所有可以交换到的元素存储起来,然后通过深搜查找
样例解析
#1
初始数列为 [1, 2, 3, 4, 5], 通过交换可得1个集合
#2
初始数列为 [1, 2, 3, 4, 5, 6, 7], 通过交换可得有3个集合
#3
初始数列为 [1, 2, 3, 4, 5, 6, 7], 通过交换可得3个集合
代码
#include <iostream>
using namespace std;
int f[105]={0},des[105]={0},d[105]={0},n;
//对数组初始化
void makeset()
{
for(int i=1; i<=n; i++)
f[i]=i;
//给每一个元素进行编号,假设每个元素为一个集合,在这几集合中的代表即为该元素
}
//递归找祖先
int getf(int v)
{
if(f[v]==v)
return f[v];
else
{
f[v]=getf(f[v]);
return f[v];
}
}
//合并
void Union(int u, int v)
{
int t1=getf(u);
int t2=getf(v);
if(t1!=t2)
{
f[t2]=t1;//靠左原理
}
}
int main()
{
cin >> n;
int flag=0;
makeset();//进行初始化
for(int i=1;i<=n;i++)
cin >> des[i];//输入目标数列
for(int i=1;i<=n;i++)
{
cin >> d[i];
if(i>d[i])
Union(i,i-d[i]);
if(i+d[i]<=n)
Union(i,i+d[i]);
}
for(int i=1;i<=n;i++)
{
if(getf(f[i])!=getf(des[i]))
{
flag=1;
break;//其中有一位无法通过交换得到即可退出循环
}
}
if(flag==0)
cout << "YES" <<endl;
else
cout << "NO" << endl;
return 0;
}