线性DP 两次最长上升子序列 1836_POJ

线性DP 两次最长上升子序列 1836_POJ

题意:
n个士兵,选ct个人出队,使得重新排队得到的队伍每个人都可以向左或向右看到无穷远,没有比他高或同样高的视觉障碍(人)。求ct最小值。

分析:

要从左无障碍的看到无限远,则需有左边的人都比他低,同理,右边也一样。故找到站到中间的一个人(or two),他的两边的最长子序列之和最大。即留下的士兵最多,即出队的人最少。

使剩下的队列满足a1 < a2 < a3 ... < a(i ) <=> a(i+1) > a(i+2) > .. a(n-1) > a(n)

 

#include < cstdio >
#include
< cstdlib >
#include
< cstring >
#include
< cmath >

int  d[ 1010 ],rev[ 1010 ],index[ 10 ];
double  hi[ 1010 ];

int  main()
{
    
int n,tmp=0,i,j,max=0,ct=0;
    
double db;
    scanf(
"%d",&n);
    
for(i=0;i<n;++i)
    
{    scanf("%lf",&hi[i]);//双精度浮点数输入须为%lf,而非%f
        d[i]=1;
        rev[i]
=1;
    }

    
//scanf("%f",&db);
    
//d[0]=1;
    for(i=1;i<n;++i)
    
{
        
for(j=0;j<i;++j)
            
if(hi[j]<hi[i]&&d[j]+1>d[i])
                d[i]
=d[j]+1;//正序以i结尾的最长上升子序列长度
    }

    
for(i=n-1;i>=0;--i)
    
{
        
for(j=n-1;j>i;--j)
            
if(hi[j]<hi[i]&&rev[i]<rev[j]+1)
                rev[i]
=rev[j]+1;//逆序以i结尾的最长上升子序列长度
    }

    
for(i=0;i<n;++i)
    
{
        
if(d[i]+rev[i]>max)//find the highest one int the middle,keep its index in record
        {
            max
=d[i]+rev[i];
            index[
0]=i;
            tmp
=0;
        }

        
else if(d[i]+rev[i]==max&&hi[i]==hi[index[0]])//&&hi[i]==hi[index[0]]漏掉则出错。此条件判断是否有两个相等的最高顶点。
        {
            index[
++tmp]=i;
        }

    }

    ct
=index[0]+1-d[index[0]]+n-1-index[tmp]+1-rev[index[tmp]];//b4 and after of 3 parts:before index[0];between o~tmp;after index[tmp]
    for(i=index[0]+1;i<index[tmp];++i)//intermediate part
        if(hi[i]<hi[index[0]])ct++;
    printf(
"%d\n",ct);
    
return 0;
}



 

你可能感兴趣的:(线性DP 两次最长上升子序列 1836_POJ)