Codeforces 607 B-Zuma 【区间DP】

题目来源:https://codeforces.com/problemset/problem/607/B
Codeforces 607 B-Zuma 【区间DP】_第1张图片
★打牌憨憨开始写区间DP啦~


翻译:

有n个点按顺序排成一行,你现在要 消去所有的点 。每次只能消去一段连续的 回文子序列,问最少需要消去多少次?


思路:

我们可以令 dp[ i ][ j ] 表示 消去区间( i , j )所需的最少步数
初始化dp为inf,我们可以得到初始条件,dp[ i ][ i ] = 1
然后用一个k作为i和j的中介 有转移方程dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);
特殊情况就是 f[ i ] = f[ j ],此时还要dp[l][r]=min(dp[l][r],dp[l+1][r-1]);
不难发现,如果j-i=1 ,会出一点问题。(例子:dp[1][2]=min(dp[1][2],dp[2][1])
我们不妨在初始条件时 初始化 dp[ i ][ i+1 ]


代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=500+5;
const int sz=1<<6;
const int inf=2e9;
const int mod=1e9+7;
const double pi=acos(-1);
typedef long long LL;
LL n,m;
int f[maxn],dp[maxn][maxn];
template<class T>
inline void read(T &x)
{
    char c;x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++) read(f[i]);
    memset(dp,127/3,sizeof dp);
    for(int i=1;i<=n;i++) dp[i][i]=1;
    for(int i=1;i<n;i++) dp[i][i+1]=(f[i]==f[i+1])?1:2;
    for(int len=2;len<n;len++){
        for(int l=1;l<=n;l++){
            int r=l+len;
            if(r>n) break;
            for(int k=l;k<r;k++){
                dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);
            }
            if(f[l]==f[r]) dp[l][r]=min(dp[l][r],dp[l+1][r-1]);
        }
    }
    cout<<dp[1][n]<<endl;
    return 0;
}

你可能感兴趣的:(动态规划)