codeforces 607B(记忆化dp,区间dp)

链接: 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

*/

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/82634765
今日推荐