杭电1280——前m大的数
还记得Gardon给小希布置的那个作业么?(上次比赛的1005)其实小希已经找回了原来的那张数表,现在她想确认一下她的答案是否正确,但是整个的答案是很庞大的表,小希只想让你把答案中最大的M个数告诉她就可以了。
给定一个包含N(N<=3000)个正整数的序列,每个数不超过5000,对它们两两相加得到的N*(N-1)/2个和,求出其中前M大的数(M<=1000)并按从大到小的顺序排列。
Input
输入可能包含多组数据,其中每组数据包括两行:
第一行两个数N和M,
第二行N个数,表示该序列。
Output
对于输入的每组数据,输出M个数,表示结果。输出应当按照从大到小的顺序排列。
Sample Input
4 4
1 2 3 4
4 5
5 3 6 4
Sample Output
7 6 5 5
11 10 9 9 8
思路:
1.初一看,这个题目很简单,只要 ( 双层循环 + 排序 )就可以解决。
但是排序是用 选择排序、冒泡排序、插入排序还是快速排序呢?
这个题目的陷阱就在用排序会超时,即使你用C++内的sort()函数(改进版的快速排序)
2.思路换一换,能否不用排序就可以按顺序输出呢?
这里提供一个思想 “ 用空间换时间 ” 就是用一个很大的数组,初始化为 0 ,数组的下标表示待排序的数字,数组的值表示待排序中这个下标值的个数。(可能听起来有点懵,没关系,看代码更好理解)
代码展示:
#include<stdio.h>
#include <iostream>
#include <algorithm>
#include<string.h>
using namespace std;
int main()
{
int m,n;
int i,j;
while (scanf("%d%d",&n,&m) != EOF)
{
int a[3001];
int sum[10001]; //定义一个很大的数组
memset(sum,0,sizeof(sum)); //数组初始化全部为 0
for (i=0;i<n;i++) //循环输入数字
scanf("%d",&a[i]);
for (i=0;i<n;i++)
for (j=i+1;j<n;j++)
sum[a[i] + a[j]]++; //循环遍历求和,和为数组下标,数组值为相同和的个数
i = 10000; //从大到小遍历数组
while (m)
{
//注释部分为另一种方法
/*if (sum[i] && m != 1)
{
printf("%d ",i);
m--;
sum[i]--;
}
if (sum[i] && m == 1)
{
printf("%d\n",i);
m--;
}
if (!sum[i])
i--;*/
while (sum[i] && m) //循环输出,当sum[i] = 1时,输出 1个i;当sum[i] = 3时,输出 3 个i; 直到 sum[i] = 0
{
if (m != 1)
printf("%d ",i);
if (m == 1)
printf("%d\n",i);
sum[i]--;
m--;
}
i--; //当 sum[i] = 0 ,下标自减。由于前面初始化 sum[] 为0,下标 != a[i]+a[j] 的,a[下标] = 0.
}
}
return 0;
}