hdu - 4628 - Pieces

题意:给出一个长度不超过16的字符串s,问最少删除多少次其中的回文串能把整个s删得干干净净(回文串可跨字母组成),共T组测试数据(T <= 10)。

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

——>>集合上的动态规划。。。和点集配对很像,这里我先求出所有的回文串,然后dp。

设d[S]表示将集合S中的字母删除需要多少步,结果就是d[(1<<n)-1];

枚举所有的S,枚举所有S的子集sub;

状态转移方程:d[S] = min(d[S], d[S^sub)] + 1](如果sub是回文串~这样才算能减一步呀);

 

#include <cstdio>

#include <cstring>

#include <algorithm>



using namespace std;



const int maxn = 16 + 1;

const int INF = 1000000000;

char s[maxn];

bool ispal[1<<maxn];

int d[1<<maxn], n;



void getPal()       //求出所有的回文串

{

    int S, i, j;

    for(S = 0; S < (1<<n); S++){

        bool ok = 1;

        int m = 0, buf[maxn];

        for(i = 0; i < n; i++) if((1<<i) & S){

            buf[m++] = s[i];

        }

        for(i = 0, j = m-1; i < j; i++, j--){

            if(buf[i] != buf[j]){

                ok = 0;

                break;

            }

        }

        ispal[S] = ok;

    }

}



void dp(){

    int S, sub;

    d[0] = 0;

    for(S = 1; S < (1<<n); S++){

        d[S] = INF;

        for(sub = S; sub > 0; sub = (sub-1) & S){

            if(ispal[sub]) d[S] = min(d[S], d[S^sub] + 1);

        }

    }

}



int main()

{

    int T;

    scanf("%d", &T);

    while(T--){

        scanf("%s", s);

        n = strlen(s);

        getPal();

        dp();

        printf("%d\n", d[(1<<n)-1]);

    }

    return 0;

}


 

 

你可能感兴趣的:(HDU)