当年toj存在的时候,我也做过这题,4年前吧
回复 20楼 StarWing83
推箱子那个就不管它了,但导弹这个有更快的方法我感兴趣,我有想过,但没想也更快的方法,能说下更快方法的思路吗?麻烦你了,谢谢!

程序代码:#include <stdio.h>
#include <stdlib.h>
#define N 100
int n, a[N], bn, b[N], c[N], d[N];
/* 数组a:保存输入的数,所在导弹的高度
数组b:保存最长降序数列,但不是最终结果。
数组c:保存数组b降序数列在a中的下标。
数组d:记下每段降序的连接下标,最主要就是这数组,只了解了这数组里的数据,了解程序是怎么把每一段数列对应的下标保存下来,这个算法就想通了。就这点难。
变量bn:记下降序数列长度 */
int main(void)
{
int i, cur;
while (scanf("%d", &n) == 1) /* 先输入有几棵导弹n */
{
for (i = 0; i < n; ++i) /* 对n个导弹指定高度 */
scanf("%d", &a[i]);
for (i = 0, bn = -1; i < n; ++i)/* 降序数列长度初始值为:-1,循环n次 */
{
if (bn == -1 || a[i] <= b[bn])/* bn等于-1时,表示测到第一棵导弹,长度bn增1,保存高度到数组b。
a[i]<=b[bn],指如测到当前导弹的高度比前一棵低,bn增1,保存这棵的高度到数组b */
b[cur = ++bn] = a[i];
else /* 否则测到的当前导弹高度大于前一棵,下面的算法是把这棵的高度插入有序的数组b里,准确的说是:找到插入点,复盖
掉这点。 */
{
int low = 0, high = bn, mid;
while (mid = (low + high) >> 1, low + 1 < high)
{
if (a[i] < b[mid])
low = mid;
else if (a[i] >= b[mid])
high = mid;
}
if (b[low] <= a[i])
b[cur = low] = a[i];
else
b[cur = high] = a[i];
}
c[cur] = i;/* 保存刚入数组b的值在数组a的下标 */
d[i] = cur ? c[cur - 1] : -1;/* 记下连接,这不好理解,如各位自己编写同样算法的程序就会知道难点在这 */
}
cur = c[bn];/* 到这是以找到最长的降序数列了,把这数列最后的一个数,也最小的数的下标赋给cur */
for (i = bn; i >= 0; --i)/* 循环把最长的降序数列保存到数组b,了解数组d,这循环才好了解。 */
{
b[i] = a[cur];
cur = d[cur];
}
for (i = 0; i <= bn; ++i)/* 输出可击落最多导弹的各个高度,也是就是最长数列 */
printf("%d ", b[i]);
putchar('\n');
}
return 0;
}

程序代码:·
·
while (low + 1 < high)
{
mid = (low + high) >> 1;/* 这个取中间值循环条件判断用不上,我把它移下来了。这样让人更好理解点 */
if (a[i] <= b[mid]) /* 加个等号 */
low = mid;
else if (a[i] > b[mid]) /* 原先有一个等号,现在去掉了 */
high = mid;
}
if (b[low] < a[i]) /* 原先这也有一个等号,现在去掉了,这样测试数据都正确了。 */
b[cur = low] = a[i];
else
b[cur = high] = a[i];
·
·

程序代码:
while (low + 1 < high)
{
mid = (low + high) >> 1;/* 这个取中间值循环条件判断用不上,我把它移下来了。这样让人更好理解点 */
if (a[i] <= b[mid]) /* 加个等号 */
low = mid;
else
high = mid;
}
if (b[low] < a[i]) /* 原先这也有一个等号,现在去掉了,这样测试数据都正确了。 */
b[cur = low] = a[i];
else
b[cur = high] = a[i];