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
题意:
给出{0, 1, ..., N−1} 的一个序列,要求通过两两交换的方式将其变为递增序列,但是每一次减缓必须用 0 与其他书进行交换。求最小交换次序。其中, N (≤10^5)。
思路:
贪心算法:要求一个问题的最优解,先求局部最优解,即就是中间每一步都要是最优解
本题中,如果当前 0 处于 i 号位,则找到数字 i 当前所处的位置,然后把 0 与 i 进行交换,此时数字i 就位于它的最终位置上,取得了最优解。
注意:
- 对于本题很容易想到一个策略:如果当前 0 处于 i 号位,则找到数字 i 当前所处的位置,然后把 0 与 i 进行交换。但是思路存在一个问题:当0处于 0 号位时,将无法继续。因此,处理这个问题,当 0 回到 0 号位时,随意选择一个还没有回到本位的数字与 0 交换,从而继续。
- 本题如果从头开始枚举,不在本位上的数,有两组数据会超时。因此设置变量 left ,来保存当前不在本位上的个数,变量k 用来表示当前不在本位的最小数字,以此进行循环
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100010;
int pos[maxn];
int main(){
int n, ans = 0;
scanf("%d", &n);
int left = n - 1, num; //left存放除 0 之外不在本位上的数的个数
for(int i = 0; i < n; i++){
scanf("%d", &num);
pos[num] = i;
if(num == i && num != 0)
left--;
}
int k = 1; //存放除0之外当前不在本位上的最小的数
while(left > 0){
if(pos[0] == 0){
while(k < n){
if(pos[k] != k){
swap(pos[0], pos[k]);
ans++;
break;
}
k++;
}
}
while(pos[0] != 0){
swap(pos[0], pos[pos[0]]);
ans++;
left--;
}
}
printf("%d\n", ans);
return 0;
}