小猴和冒泡 | ||||||
| ||||||
Description | ||||||
小猴同学遇见了一道难题:给出一个长度为n的序列,将其变成递增序列。
可能对于你来说并不算难题,因为一个qsort就完全可以解决,但是对于小猴同学来说就是个难题了,因为他只会冒泡。
冒泡的思想相信大家都会,每次比较相邻两个数的大小,如果想要得到递增序列,那么前一个数大于后一个数就要把它们交换一下位置,经过n-1趟扫描就能得到想要的递增序列。
但是冒泡的时间复杂度是O(n^2),经常会超时,我们假设每作一次交换需要1ms,而小猴同学遇到的难题时间限制是1000000ms,现在请你帮助小猴同学判断一下他的冒泡算法是否会超时。 | ||||||
Input | ||||||
本题测试数据不超过200组。对于每组测试数据,第一行输入一个整数n(1<=n<=5000),表示这个序列有n个数,接下来一行有n个数,每两个数之间用空格隔开,代表给出的序列。 | ||||||
Output | ||||||
对于每组测试数据,如果小猴程序运行的时间小于难题的时间限制,则输出"xiaohouV5!",否则输出"xiaohouTLE!"。(如果小猴程序运行的时间和限制的时间相等,则判TLE)。
| ||||||
Sample Input | ||||||
4 2 1 4 3 | ||||||
Sample Output | ||||||
xiaohouV5! | ||||||
Author | ||||||
小猴 |
做了这个题,学习了一下归并排序,也算是浅显的了解了一下归并排序和其中的特点。
思路:首先我们要知道归并排序的特点,才能做这个题,首先呢,归并排序采用了递归分治的思想,先对小的区间归并排序,再对大的区间归并排序,这样的一个算法保证了数据的相对位子,其实也就是能通过归并排序找到交换次数,这个问题我们稍后再谈,我们先对一个小小的例子进行分析(首先,如果您还不知道归并排序是什么,归并排序是怎样操作的,这里有篇博客写的还是比较好的,先学习了,再回来做题更好理解:http://www.cnblogs.com/jillzhang/archive/2007/09/16/894936.html):
假设输入的是4个数:3 2 1 4
首先递归到最深然后处理3,2这两个数,将其排序为2 3,然后递归到1 4这两个数,不需要排序,最后将其归并,处理 2 3 1 4这四个数,最终排序得到 1 2 3 4
在归并排序的操作中,是将几个数分成两个集合,对于其中两个集合的数比较大小,然后取小的放在tmp【】数组里边,其实在这个操作过程中,也就是相当于冒泡里边的交换操作,只不过在这里一次操作顶冒泡排序里边很多次操作(所以归并排序不会超时还能计算出冒泡次数),我们还是拿刚刚的例子来说,假如处理3 2这两个数的时候,首先取2放在tmp【】数组里边,然后再取3,其实就相当于冒泡里边交换一次的操作。那么在处理2 3 1 4这四个数的时候,我们首先取1放在tmp【】数组里边,然后是2、3、4,其实就相当于1和3换一次,再和2换一次,使得序列最终变成1 2 3 4.因为归并排序保证了相对位子这种特性,所以我们可以通过归并排序这样的伪交换操作,计算出冒泡排序一共需要多少次操作。
具体内容对应代码理解:
#include<stdio.h>
#include<string.h>
using namespace std;
int a[5005];
int b[5005];
int cont;
void mergesort(int l,int r)
{
int i,j,k,m;
if(l<r)
{
m=(r+l)>>1;
mergesort(l,m);
mergesort(m+1,r);
k=l;
for(i=l,j=m+1; i<=m&&j<=r;)
{
if(a[i]>a[j])
{
b[k++]=a[j++],cont+=m-(i-1);//相当于线性交换了这么多次
}
else b[k++]=a[i++];
}
while(i<=m)b[k++]=a[i++];
while(j<=r)b[k++]=a[j++];
for(i=l; i<=r; i++)a[i]=b[i];
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
cont=0;
mergesort(1,n);
//printf("%d\n",cont);
if (cont< 1000000)
{
printf("xiaohouV5!\n");
}
else
{
printf("xiaohouTLE!\n");
}
}
}