2020年牛客算法入门课练习赛1 -E 交换(水题,求循环节)

题目传送门

题目描述

牛客幼儿园的小朋友课间操时间需要按照学号从小到大排队,但是他们太小了只能站成一列顺序却不对,现在幼儿园的阿姨需要帮忙交换小朋友的位置让他们最终有序,阿姨希望能尽快完成交换操作,问最少需要交换多少次,才能使得小朋友们从小到大排好。
注意:每个小朋友的学号不同,但是未必连续,因为可能有小朋友请假了没有来。
输入描述:
第一行一个整数 N。
接下来 N 行每行一个整数,为小朋友们的队列。
输出描述:
一个整数表示小朋友们的最小交换次数。
示例1
输入

3
2
1
3

输出

1

备注:
N≤100000,其他整数均≤10^9

举个例子
num:1 2 3 4 5
5 4 3 2 1

我们可以发现5,1虽然不在自己应该在的位置,但是如果把它们两个看成整体,对于整个序列来说它们占据了排好序后5,1应该在的位置,所以对于整个序列来说是有序的,它们只是自身内部无序而已。5应该到1处,1应该到5处,形成了一个循环,所以可以将它们抽象成一个环,环内换序就可以了。
对于一个含有n个元素的循环节来说,要使其有序,要交换n-1次(前面都排好了,最后一个数自然有序就不用排了)。
上例中3在原本就在的位置,可以看成一个元素的循环节。
我们可以推断出有一个循环节,就可以少交换一次,因为n个元素的循环节,只需交换n-1次即可有序。
那么对于整个序列来说,最少交换次数为 元素总数-循环节个数。

ac:代码

#include
using namespace std;
const int maxn=1e6+100;
using namespace std;
int getMinSwaps(vector<int> &A)
{
    vector<int> B(A);
    sort(B.begin(), B.end());
    map<int, int> m;
    int len = (int)A.size();
    for (int i = 0; i < len; i++)
    {
        m[B[i]] = i;   
    }

    int loops = 0;   
    vector<bool> flag(len, false);
    for (int i = 0; i < len; i++)
    {
        if (!flag[i])
        {
            int j = i;
            while (!flag[j])
            {
                flag[j] = true;
                j = m[A[j]]; 
            }
            loops++;
        }
    }
    return len - loops;
}

vector<int> num;

int main()
{
    int n;
    for(cin>>n;n;n--)
    {
        int x;
        cin>>x;
        num.push_back(x);
    }

    int res = getMinSwaps(num);

    cout << res << '\n';
    
    ststem("pause");
    
    return 0;
}

你可能感兴趣的:(牛客)