[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 (≤105) 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交换位置。这样最终所有的数字都会在正确的位置上。
运行超时解决办法:
- 把cin、cout换为printf()、scanf()。
- 使用一个pos数组或者map结构记录各个数字的位置。
- 使用变量remain记录除了0外不在正确位置的数字的个数,在 i != 0条件下,每交换一次,remain减1,当remian==0时结束。
- 在 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;
}