题意:
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;
}