拦截导弹HDU 1257nyoj814+FIS最长上升子序列长度

服了,一直wrong answer,只好一直弄,一直改,发现只有一个地方不一样,就是数据是一组一组的,就是要不停地读。我自己只读了一次。这么点错误,弄了一下午。。。。

以下为代码:

我自己用贪心直接求得,注释部分是另一种方法,仔细观察其实是一样的。

贪心思路:用vec保存每个拦截系统的现在的最低高度。初始化为第一个导弹的高度,然后对于每个导弹,判断存不存在lower_bound(>=的第一个数),若有,更新这个值为当前高度,否则,push_back插入

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main() {
	int n = 0;
	while (scanf("%d", &n) != EOF) {
		vector<int> vec;
		int k = 0;
		scanf("%d", &k);
		vec.push_back(k);
		//int cnt = 1;
		for (int i = 1; i < n; i++) {
			scanf("%d", &k);
			//printf("%d ", cnt);
			//求最长上升子序列的长度
			/*if (vec[vec.size() - 1] < k) {
				vec.push_back(k);
			}
			else {
				vector<int>::iterator iter = lower_bound(vec.begin(), vec.end(), k);
				*iter = k;
			}*/

			//求非上升子序列的个数
			sort(vec.begin(), vec.end());
			vector<int>::iterator iter= lower_bound(vec.begin(), vec.end(), k);
			if (iter != vec.end()) {
				*iter = k;
			}
			else {
				vec.push_back(k);
			}

		}
		printf("%d\n", vec.size());
	}

	//system("pause");
	return 0;
}

另一种方法的原理是:

求最长上升子序列FIS:

      给定排好序的一堆数列中,求其的LIS长度。它的LIS长度就是它非上升子序列的个数。

注释里的就是这种方法,然后时间复杂度是n2

贪心的方法简单容易理解,而且不用动态规划。动态规划本身好理解,但是要优化成nlogn有点烦。

详情见下面这两篇文章:

扫描二维码关注公众号,回复: 8598900 查看本文章

http://www.cnblogs.com/wxjor/p/5524447.html

http://www.cnblogs.com/frankchenfu/p/7107019.html

#include<cstdio>
#include<algorithm>
const int MAXN=200001;

int a[MAXN];
int d[MAXN];

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    d[1]=a[1];
    int len=1;
    for(int i=2;i<=n;i++)
    {
        if(a[i]>d[len])
            d[++len]=a[i];
        else
        {
            int j=std::lower_bound(d+1,d+len+1,a[i])-d;
            d[j]=a[i]; 
        }
    }
    printf("%d\n",len);    
    return 0;
}

注意:在动态规划方法中,下面的else中求lower_bound其实根本没必要,也就是第二篇说的用栈模拟最长上升序列根本没必要,因为只求长度的话,只要栈顶元素永远是最新的就可以。

第一篇用“潜力”说明这种方法的必要性,我觉得牵强。根本不用这样做就能求得到长度。注意lower_bound是logn的复杂度。如果不让使用STL,可以用二分查找实现。即如第一篇的最后代码

上面是我刚才想的,我没发现有人把else中的二分查找解释的很清楚,我还以为是没用的。如果去掉这句,那么整个算法的复杂度就是O(N),也就是说,只要当前的数比栈顶大,那么就计算在内。

但是这显然与我自己想的贪心算法时间复杂度不符,而且,会出现以下的情况:

若输入是:2 5 3 4,如果只是一个个比较,把比栈顶大的入栈,计算个数,那么显然,这种情况结果是2,不是3.

我们再次观察发生了什么:当判断2的时候,虽然它比栈顶元素小,但是在else中利用二分查找找到了它的位置,此时更新那个位置,显然那个位置就是栈顶。这个元素被更新到栈顶。从而保证了算法的正确性。

也就是说:栈顶元素的更新不只是在当前元素比栈顶大的时候,同样在else中也有可能被更新。即若该元素>(栈顶+1)的元素,那么该元素必定会被更新到栈顶。

而对于当前的数<=栈顶+1的元素,这种情况同样需要执行else,只有这样,我们才能保证栈顶+1的元素是更新过的.

以此类推,我们需要保证整个栈都是充满这样的更新后的元素

如下面这种情况:2 10 6 7 3 4 5。栈的变化如下

更加理解了这个算法

发布了32 篇原创文章 · 获赞 5 · 访问量 4660

猜你喜欢

转载自blog.csdn.net/qq_38941327/article/details/89318556