以计蒜客CS109 删除最小元素习题为例:
给定有 n 个数的 A 序列:A1,A2,A3⋯An。对于这个序列,我们想得到一个子序列 Ap1,Ap2⋯Api⋯Apm(1≤p1<p2<⋯pi<⋯<pm≤n),满足 Ap1≥Ap2≥⋯≥Api≤⋯≤Apm。从 A 序列最少删除多少元素,可以得到我们想要的子序列。
输入格式
第一行输入一个整数 n,代表 A 序列中数字的个数。第二个输入 n 个整数,代表A1,A2,A3...An。
(1≤n≤1000,1≤Ai≤10000)
输出格式
输出需要删除的元素个数,占一行。
样例输入
7 3 2 4 1 2 5 3
样例输出
2
啊这道题目思路比较简单,就是从左往右一次LDS最大递减子序列和从中间到末端LCS最大递增子序列,2次DP。思路比较简单,但写了好久都没写对,一直不知道问题出在哪里。然后总结了下这类DP问题有思路但结果错误情况下的Debug通法,直接在循环里面加上输出DP矩阵的语句,然后逐行检查,一般都能找到哪里写错了。另外最好在草稿纸上先把状态方程写下来,我习惯不太好有时候图省事总是直接写代码,这样错误率也比较高。
下面附上这题代码:
#include<bits/stdc++.h>
using namespace std;
int dp[1003][1003];
int dp1[1003][1003];
int dp2[1003][1003];
int a[1003];
int main(void){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
dp1[j][i]=1;
dp2[j][i]=1;
}
}
for(int m=0;m<n;m++){
for(int i=0;i<=m;i++){
for(int j=0;j<i;j++){
if(a[j]>=a[i]){
dp1[i][m]=max(dp1[i][m],dp1[j][m]+1);
}
}
//cout<<dp1[i][m]<<" ";
}//cout<<endl;
}
for(int m=0;m<n;m++){
for(int i=0;i<=m;i++){
for(int j=i;j<m;j++){
if(a[j]<=a[m]){
dp2[i][m]=max(dp2[i][m],dp2[i][j]+1);
}
}
//cout<<dp2[i][m]<<" ";
}//cout<<endl; //就是这两行cout,非常重要
}
int max1=-99999;
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
dp[j][i]=dp1[j][i]+dp2[j][i];
max1=max(max1,dp[j][i]);
// cout<<dp2[j][i]<<" ";
}//cout<<endl;
}
cout<<n+1-max1<<endl;
return 0;
}