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
/*思路:贪心算法,即尽量每次交换使其在其应在的位置
这题想了好久,一开始的思路是想通过几个例子找出交换的规律,思考的出发点是怎么使序列能有序(这样想不出来)
想到mooc上那句话,N个数字的排列由若干个独立的环组成,解法由此产生。
对于0所在的位置,应该放上什么数字,就去找这个数字然后交换,这个操作做下去会形成环,所以当一个环内的
数字交换完以后,进入下一个环。那么交换的次数可以由环的个数,以及每个环内的元素得到.
假设遍历一个序列得到N个环,0必在一个环内,
如果环内只有一个元素,那么不需要交换
如果多元环且有0,那么只需交换元素个数减一次
如果多元环没有0,本身交换需要元素个数减一次,还有讲0换进环内,次数加一,0参与进来后,交换又得加一,
所以一共是元素数量加1*/
#include<stdio.h>
#include<stdlib.h>
int main() {
int N;
scanf("%d", &N);
int* array = (int*)malloc(N * sizeof(int));/*存储输入数据*/
int* visited = (int*)malloc(N * sizeof(int));/*是否访问过*/
int* steps = (int*)malloc(N * sizeof(int)); /*每个环的数量,这个数组可以不需要*/
for (int i = 0; i < N; i++) {
scanf("%d", &array[i]);
}
for (int i = 0; i < N; i++) {
visited[i] = 0;
}
for (int i = 0; i < N; i++) {
steps[i] = 0;
}
/*下面找环*/
int step, temp; /*step为环里元素个数*/
int flag =0;/*标记0在的环*/
for (int i = 0; i < N; i++) { /*遍历序列*/
temp = i;
step = 0;
if (visited[temp] == 1) continue;
if (array[temp] == temp) { /*只有一个元素的环*/
step++;
visited[temp] = 1;
}
else { /*开始新的环*/
while (visited[temp]==0) {
if (temp == 0) flag = 1; /*判断环内有没有0*/
visited[temp] = 1;
temp = array[temp];
step++;
}
}
if (flag == 1) {
steps[i] = 0-step; /*使0所在的环使其为负值*/
flag = 0;
}
else {
steps[i] = step;
}
}
int total = 0;
for (int i = 0; i < N; i++) {
if (steps[i] < 0) { /*0所在的环*/
total = total - steps[i]-1;
}
else if (steps[i] > 1) { /*多元环*/
total += steps[i]+1;
}
}
printf("%d", total);
return 0;
}