pku 1836 Alignment DP (LIS)
http://poj.org/problem?id=1836
其实前不久校赛的题目就是这个题目的一个简化版本,http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2403 这道题只要求出从左到右,从右到左,以及Ak1<Ak2<Ak3<...<Amid-1<Amid>Amid+1>...>Akm-2>Akm-1>Akm (k1,k2,k3....km均在1到n之间) 严格按照左边递增右边递减的序列长度去最大就好了。
这里的题意和SDUT2403差不多,只是对于第三个条件放松吧了,中间可以出现相等的。这样中间相等的那两个可能挨着也可能不挨着所以要循环遍历一次。
View 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; }