POJ 1836 Alignment 最长上升(下降)子序列(dp)

来源:互联网 发布:首席数据师by徐徐图之 编辑:程序博客网 时间:2024/04/27 16:17

题目链接:Alignment


    题目大意:给出一串士兵的身高,现在要求每个士兵都能一眼看到最左边或最右边,因此需要一些士兵出列,问最少要有多少士兵出列。

    因为士兵看到最左边或者最右边都是可以的,因此我们只要求出每个位置左边最多能留下多少人和每个位置右边最多能留下多少人,对每个位置,记录下最多左边留下多少人,然后在右面的序列中找出一个能在右面留下最多人的位置,两者加和,然后遍历所有的位置,找出最大的和,就是最多能留下多少人,用总人数减去留下的人,就是题目要求的最少出列的人数。


(又见灵魂画风)(数据来自Discuss)

    如图,黑字为高度,蓝字为从左到右的最长上升子序列长度,红字为由右到左的最长上升子序列长度(也就是从左到右的最长下降序列长度),这组数据,观察可知,当第四和第五个位置的士兵,也就是高度为1和2的士兵出列后,就可以形成一个符合题目要求的序列,因此这组数据答案为2。由左到右的最高的是第三位的5,由右到左最高的是第六位的5.

    那么,在代码中,我们要如何实现这个查找呢,很简单,只要求出每个位置的最长上升子序列长度和最长下降子序列长度,然后把每一个位置当做由左到右的最高的位置,然后向右边找由右到左最高的,也就是最长下降子序列长度最大的,两者相加得出的就是当前位置为由左到右最高的时候队列中可以留下多少士兵,然后遍历每个位置,找到这个过程中的最大值即可。这个最大值就是最终的结果。

    这里要继续吐槽POJ的数据,网上搜的题解,有相当一部分其实代码是错的,但是因为POJ的数据太水,导致了他们也通过了这个题。而且POJ的玄学问题,确实是很多......

    还是最后放代码:

#include <stdio.h>#define Max(x,y) x>y?x:yint main(){int n, i, l, ans = 0;int up[1111], down[1111];double h[1111];scanf("%d", &n);for (i = 1; i <= n; i++)scanf("%lf", &h[i]);for (i = 1; i <= n; i++)//求出每个位置的最长上升子序列长度{up[i] = 1;for (j = 1; j < i; j++)if (h[i] > h[j])up[i] = Max(up[i], up[j]+1);}for (i = n; i >= 1; i--)//求出每个位置的最长下降子序列长度{down[i] = 1;for (j = i + 1; j <= n; j++)if (h[i] > h[j])down[i] = Max(down[i], down[j]+1);}for (i = 1; i < n; i++)//遍历每个位置作为第一部分终点的情况for (j = i + 1; j <= n; j++)//遍历第一部分终点后的每个位置,找到答案最大的第二部分的起点ans = Max(ans, up[i]+down[j]);printf("%d\n", n-ans);//总人数减去留下的人数就是需要出列的人数return 0;}
    照例代码中有编译错误,一个简单的防爬虫,请见谅。

1 0
原创粉丝点击