Codeforces 28B --- pSort (并查集)

2 篇文章 0 订阅
2 篇文章 0 订阅

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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值