题目还是有难度的,涉及到lis和lds,做这道题目之前一定要先弄懂lis和lds,O(N*2)较为简单而O(N*LOGN)的算法则相对较难理解。我的博客中有相关lis和lds的介绍。这里不展开说明了。那么这题在理解了上述两种算法后其实就是枚举了。
题目要求给定一串浮点数,去掉最少的数字使得该串数字能够满足题目要求。这里详细描述一下题目的要求,因为这是解题的关键。
题目要求:
将题目中的士兵看见left or right extramety翻译过来,其实就是所有的数字排在一起可以构成一个三角形。即两边低,中间高。
那么解题的关键就是枚举中间点了。在中间点左边用lis计算出从士兵数组开始点到以中间点为末尾点的lis,在中间点右边用lds计算出从中间点后一个点到士兵数组结束点的lds,分别计算出需要删除的数字个数,两者相加,即为该情况下最少需要去掉的数字个数,那么最终结果就是所有n中情况的最小值了。
这里需要注意如下几点:
1)满足题目要求的情况下:最左边和最右边的士兵要与其它士兵同等考虑。举个例子吧!最左边的士兵身高1.2,紧邻着的士兵身高为0.5,则也不满足题目意思,必须去掉一个士兵
2)必须严格的单调递增和单调递减
3)lis求解的是以中间点为结束点的最长递增序列个数,而lds求解的则是从中间点后一个点到结束点的所有最长递减序列中最大的。两个求解的目标是不同的
下面是代码: 180K+313MS
#include <stdio.h>
#include <stdlib.h>
#define Max 1010
#define Inf 1000010
float record[Max];
float a[Max];
float c[Max];
int n;
int len;
int Binary_search1(float value){
int left=0,right=len+1,mid;
while(left<=right){
mid=(left+right)>>1;
if(c[mid]<value)
left=mid+1;
else if(c[mid]>value)
right=mid-1;
else
return mid;
}
return left;
}
int Binary_search2(float value){
int left=0,right=len+1,mid;
while(left<=right){
mid=(left+right)>>1;
if(c[mid]<value)
right=mid-1;
else if(c[mid]>value)
left=mid+1;
else
return mid;
}
return left;
}
int lis(){
c[0]=-Inf;
c[1]=a[1];
int i,j;
for(i=2;i<=len;i++)
c[i]=Inf;
int result=1;
for(i=2;i<=len;i++){
j=Binary_search1(a[i]);
c[j]=a[i];
if(i==len)
result=j;
}
return result;
}
int lds(){
c[0]=Inf;
c[1]=a[1];
int result=1;
int i,j;
for(i=2;i<=len;i++)
c[i]=-Inf;
for(i=2;i<=len;i++){
j=Binary_search2(a[i]);
c[j]=a[i];
if(j>result)
result=j;
}
return result;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%f",&record[i]);
if(n==2){
printf("0\n");
return 0;
}
len=n;
for(int i=1;i<=n;i++)
a[i]=record[i-1];
int result=n-lis();
int temp;
for(int i=0;i<n-1;i++){
len=i+1;
for(int j=1;j<=len;j++)
a[j]=record[j-1];
temp=len-lis();
len=n-1-i;
for(int j=1;j<=len;j++)
a[j]=record[i+j];
temp+=(len-lds());
if(temp<result)
result=temp;
}
printf("%d\n",result);
return 0;
}