题目链接
题意:
一个由数字组成的序列,现在要消除这段序列,每次可以消去任意一段连续的回文数字,问最少消去几次能消完。
思路:
考虑记忆化,dfs(l,r)返回消完区间[l,r]的最少次数,当lr时,返回1;接下来我们考虑如何消去区间,区间首尾不相等时,我们只可能把这个区间转化为两个连续的区间消去;区间首尾相等时,当区间长度为2或3时,一定返回1,否则,我们也可以将其转化为两个连续的区间消去,还有一种情况,就是先将中间的区间全部消去,最后剩个a[l]和a[r],再一起消去,其实可以再消去中间的最后一步上一起消去,这时候一定是回文。所以当a[l]a[r]&&len>3时,dfs(l,r)=dfs(l+1,r-1)。具体实现见代码。
点击查看代码
// #pragma GCC optimize("O3")
// #pragma G++ optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define ll long long
const int N = 500+5;
int arr[N];
int dp[N][N];
int dfs(int l,int r){if(dp[l][r]!=0x7fffffffffffffff) return dp[l][r]; //不等说明前面搜过了,不必重复搜索if(l==r) return 1; //区间内只有一个数,返回1int zuixiao=0x7fffffffffffffff; if(arr[l]==arr[r]&&r-l+1>3) zuixiao=min(zuixiao,dfs(l+1,r-1)); //当区间首尾相等且长度大于等于4时,答案之一可能是消去区间[l+1,r-1]的最少次数if(arr[l]==arr[r]&&(r-l+1==3||r-l+1==2)) zuixiao=min(zuixiao,(ll)1); //区间首尾相等并且长度为2或3,一定可以花费一次消去for(int k=l;k<r;++k){zuixiao=min(zuixiao,dfs(l,k)+dfs(k+1,r)); //消去一个区间等价于分别消去两个连续的区间}return dp[l][r]=zuixiao; //记忆化并返回
}
void solve(){int n;cin>>n;for(int i=1;i<=n;++i){cin>>arr[i];}for(int i=0;i<=n;++i){for(int j=0;j<=n;++j){dp[i][j]=0x7fffffffffffffff; //全部初始化无穷大}} cout<<dfs(1,n)<<endl; //返回消完区间[1,n]的最小次数
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int _=1;// cin>>_;while(_--)solve();return 0;
}