codeforces1132FClear the String 记忆化搜索

28 篇文章 0 订阅
5 篇文章 0 订阅

You are given a string s of length n consisting of lowercase Latin letters. You may apply some operations to this string: in one operation you can delete some contiguous substring of this string, if all letters in the substring you delete are equal. For example, after deleting substring bbbb from string abbbbaccdd we get the string aaccdd.
Calculate the minimum number of operations to delete the whole string s.

Input
The first line contains one integer n
(1≤n≤500) — the length of string s.
The second line contains the string s(|s|=n) consisting of lowercase Latin letters.

Output
Output a single integer — the minimal number of operation to delete string s.

Examples
Input

5
abaca

Output

3

Input

8
abcddcba

Output

4

给出一个字符串,每次只能删除一组相邻且相同的字母,求最少几次能把这个字符串全部删除完。
那么对于给出的字符串,我们可以进行相邻位置上的去重。得到一个新的字符串,再对这个字符串处理。
记数组dp[i][j]表示从原字符串中取出[i,j]的子串,最少删除几次能全部删完。
那么对于一个子串[i,j],仅考虑第i位的操作,那么有

  1. 独立的将s[i]删除
    此时有状态转移方程dp[i][j]=min(dp[i][j],dp[i+1][j]+1)
  2. 将s[i]与s[k]一并删除,其中s[k]==s[i]
    在这里要从区间[i,j]找出所有的k,满足s[i]==s[k],并有状态转移方程dp[i][j]=min(dp[i][j],dp[i+1,k-1]+dp[k][j])

在使用这种记录区间的dp时,要注意数组的定义,根据定义确认状态转移方程中,是否有元素重复相加或者有元素没有加入。一般记录时用一个半开半闭区间[i,j+1)表示区间[i,j]。

根据状态转移方程,我们发现如果想要求出区间[i,j],就要先求出所有的区间[i+1,k-1] 和 [k,j]。也就是先从大区间[1,n]再到最小不可分割单位[i,i],得到结果后向上返回得到[1,n]的答案。所以在这里选择记忆化搜索实现这个dp。


#include <stdio.h>
#include <climits>
#include <cstring>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <utility>
#include <vector>
#include <string>

#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return

#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;

string s;
int dp[505][505];
map<Pair,int> section;
int dfs(int left,int right);
int main(){
    ios::sync_with_stdio(false);

    int N,len=0;
    cin>>N;
    char c;
    s+='0';
    rep(i,1,N+1){
        cin>>c;
        if(c != *(s.end()-1)){
            len++;
            s+=c;
        }
    }

    mem(dp,0);
    rep(i,1,len+1){
        dp[i][i]=1;
    }

    cout<<dfs(1,len)<<endl;

    re 0;
}
int dfs(int left,int right){
    if(dp[left][right]!=0){
        ;
    }else{
        int minn=INT_MAX;
        minn=min(minn,dfs(left+1,right)+1);
        rep(i,left+2,right+1){
            if(s[i]==s[left])
                minn=min(minn,dfs(left+1,i-1)+dfs(i,right));
        }
        dp[left][right]=minn;
    }
    re dp[left][right];
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值