题意:给出一串数字,每次删一个回文子数组,剩下的拼起来接着删,求最少几次能删完。
解:第一想法是找出所有回文子数组,如果大区间是回文直接等于1。写写发现没必要,直接转就完了。
首先设dp[i][j]为区间[i,j]最少几步删完。然后套路地拿小区间去拼,没有特殊情况大区间等于两个小区间之和。
特殊情况是,删掉一个子区间后,剩下的是个回文,可以一步删完,或者一整个是个回文。这时候首先a[i]==a[j]。如果删掉一个子区间剩下的是回文,那说明另一个子区间也是回文,整体删掉步数等于dp[i+1][j-1];整体是一个回文也一样。
2还是要特判一下。回文好烦,一不小心就漏情况了。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 505 #define eps 0.00000001 #define inf 0x3f3f3f3f #define mod 1000000007 //#define int long long int dp[maxx][maxx]={0}; int a[maxx]; int n; signed main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) dp[i][i]=1; for(int len=2;len<=n;len++){ for(int i=1;i<=n-len+1;i++){ int j=i+len-1; if(len==2&&a[i]==a[j]) dp[i][j]=1; else if(len>2&&a[i]==a[j]) dp[i][j]=dp[i+1][j-1]; else dp[i][j]=inf; for(int k=i;k<=j;k++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]); } } printf("%d\n",dp[1][n]); return 0; }