// 题意:战士们站成一排,要求每个人都能看到在他左边或右边的所有人,
// 只要有另外一人不比他矮,他就无法看到尽头了,问要至少出队多少人,即是求满足条件的最长子序列
// 比如 1 2 3 4 4 3 2 1 就满足条件,但 1 2 3 3 3 2 1 不满足,因为中间有一个3不能看到左边或右边的尽头。
// 分成两半,左半部分是最长严格上升子序列,范围[1-i],长度为Len1;
// 而右半部分是最长严格下降子序列,范围[i+1-n],长度为Len2
// 需要用 LIS算法 从前往后跑一遍,然后从后往前再跑一遍
// 思路:枚举 i (1<=i<=n),利用LIS算法计算出Len1和Len2,取两者的和的最大值,最后用总人数减掉,就是需要出队的最少人数了
#include<iostream> //最长严格上升子序列算法
using namespace std;
const int MAXN=1002;
int n;
void lis(double arr[],double seq[],int num[])
{
seq[1]=arr[1];
num[1]=1;
int rear=1;
for(int i=2;i<=n;++i)
{
if(arr[i]>seq[rear])
{
seq[++rear]=arr[i];
}
else
{
int s=1,t=rear,mid;
while(s<t)
{
mid=(s+t)/2;
if(seq[mid]<arr[i])
s=mid+1;
else
t=mid;
}
seq[s]=arr[i];
}
num[i]=rear; //num[i]是记录arr[1-i]的最长严格上升子序列的长度
}
}
double arr1[MAXN],seq1[MAXN],arr2[MAXN],seq2[MAXN]; //是double类型
int num1[MAXN],num2[MAXN];
int main()
{
cin>>n;
for(int i=1;i<=n;++i)
{
cin>>arr1[i];
arr2[n+1-i]=arr1[i]; //翻转数组后再求上升子序列,相当于对原序列求下降子序列
}
lis(arr1,seq1,num1); //两次求最长严格上升子序列
lis(arr2,seq2,num2);
int res=0;
for(int i=0;i<=n;++i) //枚举中间点
res=max(res,num1[i]+num2[n-i]); //由原序列arr1 的i+1->n 映射到翻转序列arr2 的1->n-i
cout<<n-res<<endl;
return 0;
}
poj 1836 Alignment
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
POJ 1836 Alignment (LIS)
Description
#include i++ ios -
POJ1836 双向LIS
一开始没怎么看题意,以为是要问去掉几个人能使队列由矮到高排好,看了看样例好像还真是,就直接敲了一发LIS
#include i++ ios -
poj1836Alignment
打了一堆 网络连接失败 。。
#include i++ ios 网络连接 -
poj1836
简单题,求使数列程先递增后递减的形式需要去掉的数字个数。当然也可以直接递减或者只递减不递增。用最长递增子序列的方法求,然后枚举两个起点的位置即可。View Code #include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;#define maxn 1005int n;double f[maxn];int len1[maxn], len2[maxn];int main(){// freopen("t.txt&qu
#include i++ ios 递增子序列 #define