codeforces #336D Zuma

https://codeforces.com/contest/608/problem/D

题目大意:有一个序列,每次能清楚其中一个连续的回文序列,求把整个序列清零的最小操作次数。

思路:

这是一个区间DP,可以设DP[ i ][ j ]为把 i 到 j 区间的序列消除的最小次数。

那么,当a[ i ]==a[ j ]时可以分为两种情况:

1,i+1== j ,这时dp[ i ][ j ]=1;

2,i+1!= j ,这时dp[ i ][ j ]=dp[ i + 1 ][ j - 1 ];(因为在消除dp[ i + 1 ][ j -1 ]的过程中,势必会产生回文序列,这时可以把他和第i个和第j个一同消去)

那么当a[ i ]!=a[ j ]时,把区间分开DP即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
#include<string>
#include<time.h>
#define ll long long
#define PI acos(-1.0)
#define F first
#define S second
#define pb push_back
#define debug(x); printf("debug%d
",x);
#define des(x); printf("des:%s
",x+1);
#define rep(f,t) for(int i=f;i<=t;i++)
const ll INF=0x3f3f3f3f3f3f3f3f;
const int inf=0x3f3f3f3f;
const ll mod=998244353;
using namespace std;
int n;
int a[550];
int dp[600][600];
int main()
{
    scanf("%d",&n);
    memset(dp,inf,sizeof dp);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        dp[i][i]=1;
    }
    for(int len=2;len<=n;len++)
    {
        for(int i=1;i+len-1<=n;i++)
        {
            int j=i+len-1;
            if(a[i]==a[j])
            {
                if(j==i+1)
                {
                    dp[i][j]=1;
                }
                else
                {
                    dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
                }
            }
            for(int k=i;k<j;k++)
            {
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
            }
        }
    }
    printf("%d
",dp[1][n]);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/switch-waht/p/13441112.html