HDU 4628 Pieces 【状压DP+01背包】

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=4628

在这里插入图片描述


翻译:

给一个字符串,你每次只能删去其中的 回文子串(不要求连续),问最少删多少次能删完


思路:

n不超过16,那首先当然想到状压DP。我是先预处理出所有 回文子串的 所代表的数(cnt个) ,然后把这个问题抽象成 01背包 的问题,有cnt个物品,体力为(1<<n)-1 ,然后再来求就会很方便~详细见代码
注意:处理中灵活运用了 string类 的特性,比如string类重载的 +


代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<string>
using namespace std;
const int maxn=18;
const int sz=1<<16;
const int mod=1e9+7;
const int inf=2e9+7;
const double pi=3.1415926;
typedef long long LL;
int n,m;
int g[sz];
int dp[sz];
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()
{
    int t; read(t);
    while(t--){
        string s;
        cin>>s;
        int len=s.length();
        int num=1<<len,cnt=0;
        for(int i=0;i<num;i++){
            string t;
            for(int j=0;j<len;j++){
                if(i&(1<<j)){
                    t+=s[j];                           //string类特性 +重载过了
                }
            }
            int l=t.length();
            bool flag=1;
            for(int j=1;j<=l/2;j++) if(t[j-1]!=t[l-j]) {flag=0; break;}    //判断是否是回文数
            if(flag){
                g[++cnt]=i;
            }
        }
        memset(dp,127/3,sizeof dp);
        dp[0]=0;
        for(int i=1;i<=cnt;i++){            //01背包
            for(int j=num-1;j>=0;j--){
                if(!(g[i]&j)){
                    dp[g[i]|j]=min(dp[g[i]|j],dp[j]+1);
                }
            }
        }
        cout<<dp[num-1]<<endl;
    }
    return 0;
}

发布了71 篇原创文章 · 获赞 89 · 访问量 8562

猜你喜欢

转载自blog.csdn.net/weixin_43890662/article/details/98988433