​http://poj.org/problem?id=1836​

其实前不久校赛的题目就是这个题目的一个简化版本这道题只要求出从左到右,从右到左,以及Ak1<Ak2<Ak3<...<Amid-1<Amid>Amid+1>...>Akm-2>Akm-1>Akm (k1,k2,k3....km均在1到n之间) 严格按照左边递增右边递减的序列长度去最大就好了。

这里的题意和SDUT2403差不多,只是对于第三个条件放松吧了,中间可以出现相等的。这样中间相等的那两个可能挨着也可能不挨着所以要循环遍历一次。


pku 1836 Alignment DP (LIS)_iospku 1836 Alignment DP (LIS)_#include_02View Code


#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 1007
using namespace std;


int dpl[maxn],dpr[maxn];
double a[maxn];
int n;

void LIS(int flag,int *dp)
{
int i,j;
if (flag == 0)
{
dp[0] = 1;
for (i = 1; i < n; ++i)
{
int m = 0;
for (j = 0; j < i; ++j)
{
if (a[i] > a[j]) m = max(m,dp[j]);
}
dp[i] = m + 1;
}
}
else
{
dp[n - 1] = 1;
for (i = n - 2; i >= 0; --i)
{
int m = 0;
for (j = n - 1; j > i; --j)
{
if (a[i] > a[j]) m = max(m,dp[j]);
}
dp[i] = m + 1;
}

}
}
int main()
{
//freopen("in.txt","r",stdin);
int i,j;
while (~scanf("%d",&n))
{
for (i = 0; i < n; ++i) scanf("%lf",&a[i]);
LIS(0,dpl);//从左到右记录最长上升子序列
LIS(1,dpr);//从右到左记录最长上升子序列
int ans = 0;
//对于中间的那点不存在相等的情况
for (i = 0; i < n; ++i)
ans = max(ans,dpl[i] + dpr[i] - 1);
//对于中间的一点存在相等的情况,且不挨着
for (i = 0; i < n; ++i)
{
for (j = i + 1; j < n; ++j)
{
ans = max(ans,dpl[i] + dpr[j]);
}
}
printf("%d\n",n - ans);
}
return 0;
}