poj1836 原题链接:http://poj.org/problem?id=1836
Description
Write a program that, knowing the height of each soldier, determines the minimum number of soldiers which have to get out of line.
Input
There are some restrictions:
• 2 <= n <= 1000
• the height are floating numbers from the interval [0.5, 2.5]
Output
Sample Input
8 1.86 1.86 1.30621 2 1.4 1 1.97 2.2
Sample Output
4
题目大意:输入一个数列,求删除最少的数,使得从序列中任取一个数h[i],有h[1] ~ h[i]单增,或h[i] ~ h[n]单减;
思路:从1~n开始枚举i,枚举到k值时,k值作为dp1的终点,作为dp2的起点,然后分别对两边进行dp,h[1]~h[k]求最长不降子序列,h[k]~h[n]求最长不升子序列,len1,len2分别表示其长度,求出len1+len2的最大值后用n-len1-len2即为所求;
因为有一个枚举分界点的循环,如果用往常的o(n^2)的LIS算法那么复杂度为o(n^3),交上去会TLE,所以这里LIS的算法应该使用o(nlogn)的算法,详细内容我写在另外一篇博客:http://blog.youkuaiyun.com/acm513828825
很遗憾写了很久还是没有对,有dalao能够帮我看一下更好,以下为我的错误代码:
#include<iostream>
#include<cstdlib>
#include<cstdio>
using namespace std;
float arr[1001];
float ans[1001];
float arr2[1001];
int binary_search(int i,int len){
int left,right,mid;
left=0,right=len;
while(left<right){
mid = left+(right-left)/2;
if(arr[mid]>=ans[i]) right=mid;
else left=mid+1;
}
return left;
}
int binary_search_2(int i,int len){
int left,right,mid;
left=0,right=len;
while(left<right){
mid = left+(right-left)/2;
if(arr[mid]<=ans[i]) right=mid;
else left=mid+1;
}
return left;
}
int main()
{
int n;
cin>>n;
int len1=0;
int len2=0;
for(int i=1;i<=n;i++)
{
cin>>ans[i];
}
int Max=1;
for(int k=1;k<=n;k++)
{
arr[0]=-1;
arr[1]=ans[1];
len1=1;
for(int i=1+1;i<=k;i++)
{
if(arr[len1]<ans[i])
{
len1++;
arr[len1]=ans[i];
}
else
{
int pos=binary_search(i,len1);
arr[pos]=ans[i];
}
}
if(k<=n-1)
{
arr2[1]=ans[k+1];
len2=1;
arr2[0]=-1;
for(int j=k+2;j<=n;j++)
{
if(arr[len2]>ans[j])
{
len2++;
arr2[len2]=ans[j];
}
else
{
int pos2=binary_search_2(j,len2);
arr2[pos2]=ans[j];
}
}}
else len2=0;
if(Max<len1+len2)
{
Max=len1+len2;
}
}
cout<<n-Max<<endl;
}
这里为正确代码,摘自:http://blog.youkuaiyun.com/lyy289065406/article/details/6648129
//Memory Time
//232K 391MS
//O(n*logn)算法,注意LIS和LDS使用不同的二分法
#include<iostream>
using namespace std;
const int inf=3;
//ord[]为不降序列
//二分法搜索digit,若str中存在digit,返回其下标
//若不存在,返回str中比digit小的最大那个数的(下标+1)
int binary_search_1(double ord[],double digit,int head,int length)
{
int left=head,right=length;
int mid;
while(right!=left)
{
mid=(left+right)/2;
if(digit==ord[mid])
return mid;
else if(digit<ord[mid])
right=mid;
else
left=mid+1;
}
return left;
}
//ord[]为不升序列
//二分法搜索digit,若str中存在digit,返回其下标
//若不存在,返回str中比digit大的最小那个数的(下标+1)
int binary_search_2(double ord[],double digit,int head,int length)
{
int left=head,right=length;
int mid;
while(right!=left)
{
mid=(left+right)/2;
if(digit==ord[mid])
return mid;
else if(digit>ord[mid])
right=mid;
else
left=mid+1;
}
return left;
}
int main(int i,int j)
{
int n; //士兵数
while(cin>>n)
{
double* h=new double[n+1];
for(i=1;i<=n;i++)
cin>>h[i];
int max=0;
for(int m=1;m<=n;m++) //对身高队列每一个值作为分界点,进行枚举
{
double* ord=new double[n+1];
/*Dp-(0~m)-LIS*/
ord[0]=-1; //下界无穷小
int len_LIS=1;
for(i=1;i<=m;i++)
{
ord[len_LIS]=inf; //上界无穷大
j=binary_search_1(ord,h[i],0,len_LIS);
if(j==len_LIS) //sq[i]大于ord最大(最后)的元素
len_LIS++;
ord[j]=h[i];
}
len_LIS--; //减去ord[0]的长度1
/*Dp-(m+1~n)-LDS*/
ord[m]=inf; //下界无穷大
int len_LDS=1;
for(i=m+1;i<=n;i++)
{
ord[m+len_LDS]=-1; //上界无穷小
j=binary_search_2(ord,h[i],m,m+len_LDS);
if(j==m+len_LDS) //sq[i]大于ord最小(最后)的元素
len_LDS++;
ord[j]=h[i];
}
len_LDS--; //减去ord[m]的长度1
//max为对于当前m的 最长不升子序列LIS 和 最长不降子序列LDS 长度之和
if(max<len_LIS+len_LDS)
max=len_LIS+len_LDS;
delete ord;
}
cout<<n-max<<endl;
delete h;
}
return 0;
}