链接: http://codeforces.com/problemset/problem/607/B
题意: 现在给你一个序列,你可以拿走一个连续的子串,如果这个子串是回文串,花费为1, 剩下的接起来,直到拿完,求最小花费。
思路: 区间dp呀。 用记忆化更好想一点。dp[ l ][ r ] 表示l到r 的最小花费。那么边界条件? 如果当前的l r 是一个回文串,那么就可以直接返回了,花费为1 ,在这里不能直接考虑拿掉中间的子串,,一开始我就这么想,然后就掉坑里了,我们当然要考虑两个端点了,如果两个端点是相同的,那么我可以拿掉这两个但是却不用花费,因为我在拿里边的时候肯定会花费一定的money ,那么我一定可以使得里边剩下一部分为一个回文串,还有一种情况就是分开取呗,就是dp[ l ][ r ] =(dp[ l ][ k ]+dp[ k+1 ][ r ] )
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =505;
const int inf= 0x3f3f3f3f;
int dp[N][N];
int s[N];
int n;
int dfs(int l,int r)
{
if(l>r) return 1;
if(dp[l][r]!=-1) return dp[l][r];
if(l==r){
return dp[l][r]=1;
}
int res=inf;
if(s[l]==s[r]) res=min(res,dfs(l+1,r-1));
for(int k=l;k<r;k++){
res=min(res,dfs(l,k)+dfs(k+1,r));
}
return dp[l][r]=res;
}
int main()
{
memset(dp,-1,sizeof(dp));
cin>>n;
for(int i=1;i<=n;i++) cin>>s[i];
int ans=dfs(1,n);
cout<<ans<<endl;
return 0;
}
/*
2
1 1
4
1 2 3 1
*/