现在的位置: 首页 > 综合 > 正文

NIOP 1999 导弹问题 最长升降序子序列 DP[小思路]

2012年09月15日 ⁄ 综合 ⁄ 共 1204字 ⁄ 字号 评论关闭

题目描述

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

输入格式

输入数据为两行,
第一行为导弹的数目N(n<=1000)
第二行导弹依次飞来的高度,所有高度值均为不大于30000的正整数。

输出格式

输出只有一行是这套系统最多能拦截的导弹数和要拦截所有导弹最少要配备这种导弹拦截系统的套数。两个数据之间用一个空格隔开.

样例输入

8389 207 155 300 299 170 158 65样例输出

6 2

三维状态图像

#include<iostream>
using namespace std;

int max( int a,int b ){ return a>b?a:b; }

int main()
{
 	int n;
 	int date[1000];
 	int DP1[1000];
 	int count[1000];
 	for( int i=0;i<1000;i++ )
 		 date[i]=DP1[i]=count[i]=0;
 		 
 	scanf( "%d",&n );
 	for( int i=0;i<n;i++ )
	 	 scanf( "%d",&date[i] );
 	
 	int ans1=0;
 	for( int i=0;i<n;i++ )
 	{
 		 for( int j=0;j<i;j++ )
 		 	  if( date[i]<date[j] )
 		 	  	  DP1[i]=max(DP1[i],DP1[j]);
 		 DP1[i]++;
 		 ans1=max( ans1,DP1[i] );
 		 //count[DP[i]]++;
    }
    int ans2=0;
    for( int i=0;i<n;i++ )
 	{
	 	 DP1[i]=0;
 		 for( int j=0;j<i;j++ )
 		 	  if( date[i]>date[j] )
 		 	  	  DP1[i]=max(DP1[i],DP1[j]);
 		 DP1[i]++;
 		 ans2=max( ans2,DP1[i] );
 		 //count[DP[i]]++;
    }
    printf( "%d %d\n",ans1,ans2 );
 	return 0;
}

第一问很简单。直接最长降序子序列。
那么第二问怎么办?开始想了很久没有想通。我简单的认为只是在第一问求出的基础上求出相应DP值的个数最多的那个就是答案了。这么想看上去有道理。因为最高的这么打下来,会消灭很多比他低的,有多少个1就可以发多少枚炮弹,如果剩余了2的话,就以2为起始点放炮。这样看上去很正确,但是实际上却是错的。为什么?因为DP的标号不代表高度。例如DP[I]=2,DP[J]=1;可以说明high[I]>high[J]吗?不行。既然这样不成立,那我的那种按DP标号来进行判断的方式当然不成立了。
举一个很小的例子,2 5 3 4 这样我算出来会是2,实际上却要3枚才能打完。
正确的思路呢?每颗炮弹都要被击中,比当前点高的又在后面的炮弹就打不中了。这样就转化为就最长升序子序列了。

抱歉!评论已关闭.