洛谷p1020导弹拦截

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是不大于50000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

这题有点难度,是线性动归,最长上升子序列和二分查找的结合,我先来说说这两个东西:

1.线性动归,即由初始状态开始,通过对中间阶段决策的选择,达到结束状态。这些决策形成了一个决策序列,同时确定了完成整个过程的一条最优的活动路线。状态转移方程为fk+1(i) = min{ fk(j) + u(i,j) }

2.二分,我们找一位同学随便写一个1-30之间的整数X,大家可以猜一个整数,我会提示你“大了”,或者“小了”,或者“恭喜你猜中了!”我们每次都猜测区间中间点,这样每次都可以把猜测的区间缩小一半。由于30/2^5<1,因此5次之内就一定可以找出答案。这就是二分的思想,基于这种思想的查找就是二分查找。大笑.

二分查找算法自然语言描述: 

1、需要设置三个指针low、high、mid表示查找区间的左端点、右端点和中间位置;

 2、当low<=high时,二分查找: (1)求mid=(low+high)/2,需要特别注意,mid设置的数据类型不能出现(low+high)数值越界问题; (2)如果目标值大于mid单元值,那么low=mid+1,继续二分; (3)如果目标值小于mid单元值,那么high=mid-1,继续二分; (4)如果目标值等于mid单元值,返回查找结果并退出查找。

 3、返回没有查到

3.最长上升子序列:算法:动态规划
                               令f[i]表示以ai为结尾的最长上升子序列的长度

                               转移方程: 当1<=j<i,且a[j]<a[i]时,f[i]=max(f[j])+1

                                时间复杂度:O(N^2)

说了这多,该说题了尴尬

这题答题思路就是分成两块,1.求最长上升子序列;2.二分:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int a[100009],f[100009];
int ans1=0,ans2=0;
int main()
{
	int n=0;
	int l,r,mid;
	f[0]=2147483647;
	while(scanf("%d",&a[++n])!=EOF)    //while式读入,读到control+Z会停止读入
	{
		continue;
	} 
	n--;
        for(int i=1;i<=n;i++)第一问
	{
		if(f[ans1]>=a[i])
		{
			f[ans1+1]=a[i];
			ans1++; 
                }
                else 
		{
			l=0;r=ans1;
			while(l<r)//二分核心代码
			{
				mid=(l+r)/2;//取中
				if(f[mid]>=a[i])
				{
					l=mid+1; //右边走1步
				}
				else
				{
					r=mid; //左边为中间
				}
                       }
                       if(l!=0)
		       {
			   f[l]=a[i];
		       }
                  }
           }
	memset(f,-1,sizeof(f));//清空f
        for(int i=1;i<=n;i++)//第二问
	{
		if(f[ans2]<a[i])
		{
			f[ans2+1]=a[i];
			ans2++;
                }
               else 
	       {
			l=0;r=ans2;
			while(l<r)
			{
				mid=(l+r)/2;
				if(f[mid]>=a[i])//同上
				{
					r=mid;
				}
				else
				{
					l=mid+1;    
				}
			}
                        f[l]=a[i];
                }
        }
        printf("%d\n%d",ans1,ans2);
}

二分的话我建议做

P1316 丢瓶盖

P1182 数列分段Section II
P2678 跳石头


猜你喜欢

转载自blog.csdn.net/lyt0707/article/details/80063411