数列有序!
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 99399 Accepted Submission(s): 41560
Problem Description
有n(n<=100)个整数,已经按照从小到大顺序排列好,现在另外给一个整数x,请将该数插入到序列中,并使新的序列仍然有序。
Input
输入数据包含多个测试实例,每组数据由两行组成,第一行是n和m,第二行是已经有序的n个数的数列。n和m同时为0标示输入数据的结束,本行不做处理。
Output
对于每个测试实例,输出插入新的元素后的数列。
Sample Input
3 3 1 2 4 0 0
Sample Output
1 2 3 4
Author
lcy
Source
问题链接:HDU2019 数列有序!。
问题简述:(略)
问题分析:
也许对于本题,会考虑用插入排序来做,那就有点绕远了。只要做排序就有可能可能做数据交换,处理时间就长了。
可以考虑输入的n个数据先存放在数组中,再输出。
各种方案中,一边输入数据,一边输出数据,并且在适当位置输出m的做法,应该是优选方案。因为这样做,省去了数组,没有使用额外空间。
程序说明:
解法二不是优选方案,但也是一种常见的解法。输入数据放到数组中,同时计数小于m的数据个数p,根据p值输出时在适当位置输出m。。
AC的C语言程序如下(正解):
/* HDU2019 数列有序! */
#include <stdio.h>
int main(void)
{
int n, m, val, i;
while(scanf("%d%d", &n, &m) != EOF) {
if(n == 0 && m == 0)
break;
if(n == 0) {
// n=0时,只需要输出m
printf("%d\n", m);
} else {
// 读入n个数据,同时输出数据,并且在适当位置输出m
int flag = 1;
for(i=0; i<n; i++) {
scanf("%d", &val);
if(flag && val >= m) {
if(i == 0)
printf("%d", m);
else
printf(" %d", m);
flag = 0;
}
if(i>0 || !flag)
printf(" ");
printf("%d", val);
}
if(flag)
printf(" %d", m);
printf("\n");
}
}
return 0;
}
AC的C语言程序如下(解法二):
/* HDU2019 数列有序! */
#include <stdio.h>
int main(void)
{
int n, m, a[100+1], i;
while(scanf("%d%d", &n, &m) != EOF) {
if(n == 0 && m == 0)
break;
if(n == 0) {
// n=0时,只需要输出m
printf("%d\n", m);
} else {
// 读入n个数据
int p = 0;
for(i=0; i<n; i++) {
scanf("%d", &a[i]);
if(a[i] < m)
p++;
}
// 输出结果
for(i=0; i<n; i++) {
if(i == p) {
if(i > 0)
printf(" ");
printf("%d", m);
}
if(i > 0 || i >= p)
printf(" ");
printf("%d", a[i]);
}
if(p == n) {
printf(" %d\n", m);
} else
printf("\n");
}
}
return 0;
}
方案3:输入数据时,将m与输入数据一起放入数组中,然后一起输出。这个方案的特点是输出部分逻辑相对简单。
AC的C语言程序如下:
/* HDU2019 数列有序! */
#include <stdio.h>
int main(void)
{
int n, m, a[100+1], i, j;
while(scanf("%d%d", &n, &m) != EOF) {
if(n == 0 && m == 0)
break;
if(n == 0) {
// n=0时,只需要输出m
printf("%d\n", m);
} else {
// 读入n个数据到数组a,并且将m插入到a的适当位置
int flag = 1;
for(i=0,j=0; i<n; i++,j++) {
scanf("%d", &a[j]);
if(flag && a[j] > m) {
a[j+1] = a[j];
a[j] = m;
j++;
flag = 0;
}
}
if(i == j) // m还没有插入到数组a中,则放在最后
a[n] = m;
// 输出结果
for(i=0; i<=n; i++) {
if(i > 0)
printf(" ");
printf("%d", a[i]);
}
printf("\n");
}
}
return 0;
}
方案4:先输入数据到数组中,然后用二分查找法找出m应该在的位置,然后输出结果。该方案逻辑太复杂,但是其逻辑也许有参考价值。
AC的C语言程序如下:
/* HDU2019 数列有序! */
#include <stdio.h>
int main(void)
{
int n, m, a[100+1], p, start, end, i;
while(scanf("%d%d", &n, &m) != EOF) {
if(n == 0 && m == 0)
break;
if(n == 0) {
// n=0时,只需要输出m
printf("%d\n", m);
} else {
// 读入n个数据
for(i=0; i<n; i++)
scanf("%d", &a[i]);
// 用二分法找出m在a中的位置p,即满足a[p-1]<=m并且m<=a[p]
// 需要考虑到特殊情况,即m在最前面(第1个)和m在最后面(第n个)的情况
// 找到m在a中的位置后,不必将m插入到a中,只需要输出时在合适位置输出即可
start = 0;
end = n - 1;
p = 0;
while(start < end) {
p = (start + end) / 2;
if(a[p] == m)
break;
else if(a[p] < m)
start = ++p; // 关键:改变start值的同时,要改变p值
else if(a[p] > m)
end = --p; // 关键:改变end值的同时,要改变p值
}
if(a[p] < m) // 关键:最后的调整
p++;
}
// 输出结果
for(i=0; i<n; i++) {
if(i == p) {
if(i > 0)
printf(" ");
printf("%d", m);
}
if(i > 0 || i >= p)
printf(" ");
printf("%d", a[i]);
}
if(p == n) {
printf(" %d\n", m);
} else
printf("\n");
}
return 0;
}