2013年浙江大学免试研究生上机考试真题。
原题链接:PTA | 程序设计类实验辅助教学平台
题目描述
给定包含数字 {0, 1, 2,..., N−1} 的任一排列,很容易对它们进行升序排序。 但是如果只允许使用Swap(0, *) 操作呢? 例如,要对 {4, 0, 2, 1, 3} 进行排序,我们通过以下方式应用Swap操作达到排序的目的:
Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}
现在要求找到对 N 个非负整数的给定排列进行排序所需的最小交换次数。
输入格式
每个输入文件包含一个测试用例,第一行为一个正整数N (≤1E5),第二行为一个排列序列 {0, 1, ..., N−1}。 一行中的所有数字都用空格分隔。
输出格式
对于每种情况,只需在一行中打印对给定排列进行排序所需的最小交换次数。
输入样例
10
3 5 7 2 6 4 9 0 8 1
输出样例
9
题目分析
浙大讲解视频:数据结构_浙江大学_中国大学MOOC(慕课)
排序的结果就是使每个数字在其对应的索引上,即a[0] = 0,...,a[N-1] = N-1。核心点在于:N个数字的排列由若干个独立的环组成。在环内对元素进行交换即可使数据归位。
一个包含n个数,且其中含0的环,需要n-1次Swap(0, *)使所有数字归位;对于一个包含n个数,且其中不含0的环,需要先进行一次Swap(0, *)使0入环,再进行(n+1)-1次Swap(0, *)使所有数据归位,合计共进行了n+1次交换;对于已经归位的单元素环,直接continue。
代码
使用C语言实现。
#include <stdio.h>
#define MAXN 100000
int a[MAXN];
int SwapNum(int a[], int N);
int main() {
int N;
scanf("%d", &N);
for (int i = 0; i < N; i++)
scanf("%d", &a[i]);
int re = SwapNum(a, N);
printf("%d", re);
return 0;
}
int SwapNum(int a[], int N) {
int ans = 0, count = 0;
int temp_idx;
int contain_0 = 0; // 环内是否包含0
for (int i = 0; i < N; i++) {
if (a[i] == i) // 已经归位
continue;
while (a[i] != i) {
if (a[i] == 0)
contain_0 = 1; // 环内包含0
temp_idx = a[i];
a[i] = i;
i = temp_idx;
count++;
}
if (contain_0) // 包含0
ans += (count - 1);
else // 不包含0
ans += (count + 1);
contain_0 = 0;
count = 0;
}
return ans;
}
测试结果