<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">最近在上数据结构和算法基础, 有一个附加题。要求如下:</span>
5-1 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 所在的下标对应的数进行交换,以保证每一次交换都能有一个数字被放到正确的位置。
然而,这里面存在一些特殊情况,即 0 已经回到了Array[0], 而数组中别的数还没排序完成。
没有办法,只能选择用0 与第一个排序错误的数进行Swap, 而这次Swap是没有完成排序一个数的任务的,但我们别无选择。
在这样的思路下,我自己先写了一个程序,然而OJ系统的结果是:在一些例子的情况下运行超时。
代码如下:
#include <stdio.h>
#include <stdlib.h>
int *Array, NumNotPos, NumSwap;
void Swap(int a, int b, int N);
void Sort(int N);
void Read(int N);
int main(int argc, char const *argv[])
{
int N;
scanf("%d", &N);
Read(N);
Sort(N);
printf("%d\n", NumSwap);
system("pause");
return 0;
}
void Read(int N)
{
Array = (int *)malloc(N * sizeof(int));
int i = 0;
while (i < N)
{
scanf("%d", &Array[i]);
i++;
}
/*
Array[0] = 3;
Array[1] = 5;
Array[2] = 7;
Array[3] = 2;
Array[4] = 6;
Array[5] = 4;
Array[6] = 9;
Array[7] = 0;
Array[8] = 8;
Array[9] = 1;
*/
}
void Sort(int N)
{
int i = 0;
while (i < N)
{
if (Array[i] != i)
NumNotPos++;
i++;
}
do
{
if (Array[0] == 0 && NumNotPos != 0)
{
int j = 1;
while(Array[j] == j && j < N)
{
j++;
}
Swap(0, j, N);
NumNotPos++;
}
if (NumNotPos != 0)
{
int j = 0;
while (Array[j] != 0 && j < N)
j++;
Swap(0, j, N);
NumNotPos--;
if (Array[0] == 0)
NumNotPos--;
}
} while (NumNotPos > 0);
}
void Swap(int a, int b, int N)
{
NumSwap++;
int i, temp, FirIndex, SecIndex;
i = FirIndex = SecIndex = 0;
while (i < N)
{
if (Array[i] == a)
FirIndex = i;
if (Array[i] == b)
SecIndex = i;
if (FirIndex && SecIndex)
break;
i++;
}
temp = Array[FirIndex];
Array[FirIndex] = Array[SecIndex];
Array[SecIndex] = temp;
}
想了很久,自我感觉已经没法优化了,结果还是超时。。。
上google! 1s 出结果,找到了一个似乎和我一样在浙大上PTA的同学技术博客。
点击打开链接 http://blog.csdn.net/xyt8023y/article/details/47210245
搬运至此:
#include <stdio.h>
int findNotOK(int* arr,int begin,int end) //从begin开始往后寻找未到位的数
{
for(int i=begin;i<end;i++)
{
if(arr[i]!=i)return i;
}
return 0;
}
int main()
{
int n;
scanf("%d",&n);
int* arr = new int[n];
int i,t;
for(i=0;i<n;i++)
{
scanf("%d",&t);
arr[t]=i;
}
int tmp = 0;
int count=0;
int firstPos = 1;
firstPos = findNotOK(arr,firstPos,n);
while(firstPos) //还有未到位的数字
{
if(arr[0]==0) //如果0到位了,则与未到位的firstPos交换
{
arr[0] = arr[firstPos];
arr[firstPos] = 0;
count++;
}
while(arr[0]!=0) //如果0不到位,则循环与自己所指向的值交换
{
tmp = arr[0];
arr[0] = arr[tmp];
arr[tmp] = tmp;
count++;
}
firstPos = findNotOK(arr,firstPos,n); //此时0归位了,找到下一个未到位的数字
}
printf("%d\n",count);
return 0;
}
对比起来,思路上基本是一致的,但在确认排序完成和寻找Swap下标的实现上存在不同。但在浙大PTA中能够通过。
结论:自己的实现总存在着大量的循环确认未排序数的个数,并且循环寻找Swap下标。
对比第二份代码,我发现这样的循环存在太多的冗余信息。
而事实上确如第二份代码中的实现,第一个未排序完成数的下标,包含了两份信息:
1、排序是否完成
2、若没完成,Array[0] == 0 时0 的交换对象。
这确实值得我学习,在满足需求的情况下,精准的定位需要的信息量,而不是盲目的获取大量无用信息。