导读
①区间DP
②最长公共子序列
③最长回文子序列
我觉得每种方法都值得一看.
#include <bits/stdc++.h>
using namespace std;
const int maxn=5009;
inline int max(int a,int b){ return a>b?a:b; }
int n;
int a[maxn],b[maxn],top;
int dp[maxn][maxn][2],ans;
void init(){
for(int i=1;i<=top;i++)
for(int j=1;j<=top;j++)
for(int q=0;q<=1;q++)
if(i!=j)
dp[i][j][q]=1e9;
}
int main()
{
cin >> n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i] );
if(a[i]==a[i-1]) continue;
else b[++top]=a[i];//变成连通块减小时间复杂度
}
for(int len=1;len<=top;len++)
for(int l=1;l+len-1<=top;l++)
{
int r=l+len-1;
//对于长度为len的区间,可以转移到len+1的区间
dp[l-1][r][0]=min(dp[l-1][r][0],dp[l][r][0]+(b[l-1]!=b[l]));//往左转移一个区间长度
dp[l-1][r][0]=min(dp[l-1][r][0],dp[l][r][1]+(b[l-1]!=b[r]));
dp[l][r+1][1]=min(dp[l][r+1][1],dp[l][r][0]+(b[l]!=b[r+1]));//往右转移一个区间长度
dp[l][r+1][1]=min(dp[l][r+1][1],dp[l][r][1]+(b[r]!=b[r+1]));
}
cout<<min(dp[1][top][0],dp[1][top][1])<<endl;
}
枚举起始点k,那么分成了[1,k-1]和[k+1,n]两个区间
#include <bits/stdc++.h>
using namespace std;
const int maxn=5009;
inline int max(int a,int b){ return a>b?a:b; }
int n;
int a[maxn],s[maxn],top;
int dp[maxn][maxn],ans;
int isok(int q,int w)
{
//求q到1和w到top的最大公共子序列
int ans=0,xian=max(q,n-w+1);
for(int i=0;i<=xian;i++) dp[1][i]=dp[i][1]=0;
for(int i=q,x=1;i>=1;i--,x++)
for(int j=w,y=1;j<=top;j++,y++)
{
if(s[i]==s[j]) dp[x][y]=dp[x-1][y-1]+1;
else dp[x][y]=max(dp[x-1][y],dp[x][y-1]);
ans=max(dp[x][y],ans);
}
return ans;
}
int main()
{
cin >> n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i] );
if(a[i]==a[i-1]) continue;
else s[++top]=a[i];
}
for(int i=1;i+2<=top;i++)//选定i+1为起始点
ans=max(ans, isok(i,i+2) );
cout<<top-ans-1;
}
实测92ms,快到爆炸有没有!!
#include <bits/stdc++.h>
using namespace std;
const int maxn=5009;
inline int max(int a,int b){ return a>b?a:b; }
int n;
int a[maxn],s[maxn],b[maxn],top;
int dp[maxn][maxn],ans;
int main()
{
cin >> n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i] );
if(a[i]==a[i-1]) continue;
else s[++top]=a[i];
}
for(int i=1;i<=top;i++) b[i]=s[top-i+1];
for(int i=1;i<=top;i++)
for(int j=1;j<=top;j++)
{
if(b[i]==s[j]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
ans=max(ans,dp[i][j]);
}
cout<<top-1-ans/2;
}