[PAT]1067 Sort with Swap(0, i) (25 分)(运行超时解决办法)

一、题意

Given any permutation of the numbers {0, 1, 2,..., N−1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:

Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}

Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.

Input Specification:

Each input file contains one test case, which gives a positive N (≤10​5​​) followed by a permutation sequence of {0, 1, ..., N−1}. All the numbers in a line are separated by a space.

Output Specification:

For each case, simply print in a line the minimum number of swaps need to sort the given permutation.

Sample Input:

10
3 5 7 2 6 4 9 0 8 1

Sample Output:

9

二、题解 

题目大意是,给出一个无序序列,要求只能使用swap(0,i)操作,即只能交换数字0和数字i的位置,对序列中的数字进行交换为位置,使用最少的交换次数,使序列有序。

第一次做时没有看好题意,以为可以使用swap(x, y),交换任意两数字的位置,答案显然不满足题意。最后看题解才恍然大悟。

另一个问题是,在修改完之后样例1、2一直运行超时,对代码进行了一些优化才顺利AC。

题解,因为只能使用数字0与其他数字进行交换,考虑到当数字0在 i 处,当 i != 0时,理应在 i 位置的数字一定在一个错误的位置,所以可以用0与 i 位置正确的数字的交换位置。当i == 0时,倘若所有的数字都排好序了,那么就结束,若存在一个数不在正确的位置上,就把它与0交换位置。这样最终所有的数字都会在正确的位置上。

运行超时解决办法:

  1. 把cin、cout换为printf()、scanf()。
  2. 使用一个pos数组或者map结构记录各个数字的位置。
  3. 使用变量remain记录除了0外不在正确位置的数字的个数,在 i != 0条件下,每交换一次,remain减1,当remian==0时结束。
  4. 在 i==0 条件下,需要找第一个不在正确位置的数字,使用变量k记录这个位置,下次再找下一个时直接从k开始往后找(不必从0开始找)。

AC代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int n;
    scanf("%d", &n);
    vector<int> nums;
    vector<int> pos(n+1);
    int index;

    int remain = n-1;//记录除了0之外所有数字,不在正确位置的数字的个数

    for(int i=0; i<n; i++) {
        int temp;
        scanf("%d", &temp);

        pos[temp] = i;//记录数字temp的位置
        //cin>>temp;
        nums.push_back(temp);
        if(temp == 0) {
            index = i;
        }
        if(temp == i && temp != 0) {
            remain --;
        }
    }

    int k = 1;
    int ans = 0;

    while(true) {
        //若0在正确的位置上,找第一个不在正确的位置的数与0换
        if(index==0) {
            int f = 0;
            int sindex;

            if(remain == 0) {
                break;
            }

            //找第一个不在正确的位置的数
            //因为k是从1开始的,可以确定在(0,k)上的数字都在正确的位置上
            for(int i=k; i<nums.size(); i++) {
                if(nums[i] != i) {
                    f = 1;
                    sindex = i;
                    k = i ;
                    break;
                }
            }

            if(f == 0) {
                break;
            }

            ans ++;

            pos[nums[index]] = sindex;
            pos[nums[sindex]] = index;

            int temp = nums[index];
            nums[index] = nums[sindex];
            nums[sindex] = temp;

            //swap(nums[index], nums[sindex]);
            index = sindex;
        } else {//若0不在正确的位置上,把理论上在这个位置的数字换过来

            int sindex;
            sindex = pos[index];
            ans ++;

            pos[nums[index]] = sindex;
            pos[nums[sindex]] = index;

            int temp = nums[index];
            nums[index] = nums[sindex];
            nums[sindex] = temp;

            index = sindex;
            remain --;

            if(remain == 0) {
                break;
            }
        }
    }
    printf("%d\n", ans);
    //cout<<ans<<endl;

    return 0;
}

 

posted on 2019-08-31 21:07  刘好念  阅读(2)  评论(0编辑  收藏  举报  来源