HDU 4295 状态压缩dp + KMP

来源:互联网 发布:淘宝玛卡是真的吗 编辑:程序博客网 时间:2024/06/05 16:08

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4295

题意:给你一个字符串和他的4个子串,将这4个子串放到原串里面(可以重叠),问你最多能覆盖多少个字符,最少能覆盖多少个字符

解析:网赛的时候DP还是太水了,居然不敢想这个题目,现在看下,其实这个题目还是不难的,只是不好写,用KMP预处理子串可以插入的位置,dp【i】【j】【k】表示位置i,4个字符串的使用状态为j,k表示 从i往后已经覆盖了K个了,状态出来了,转移应该不难,注意:一个位置可以放多个串,这是难点,不过经过预处理就好了,一次性在某个位置放很多个串。

代码写的很挫,我以为预处理了这么多,应该蛮快的,没想到卡时间过的,看解析够了。。。代码惨不忍睹


#include<stdio.h>#include<string.h>#include<cstring>#include<algorithm>#include<vector>using namespace std;const int maxn = 4100;const int maxm = 70;int dp[maxn][20][maxm][2],ok[4][maxn],next[maxm],n,m,l[4],son[4][4];char s[maxn],p[4][maxm];vector<int> h[maxn];void set_next(int id);void kmp(int id);void init();void solve();int main(){    while(scanf("%s",s) != EOF)    {        n = strlen(s) , m = 0;        for(int i = 0; i < 4; i ++) scanf("%s",p[i]),l[i] = strlen(p[i]),m = max(m,l[i]);        init();        solve();    }    return 0;}void init(){    memset(ok,false,sizeof(ok));    memset(son,false,sizeof(son));    for(int i = 0; i < 4; i ++) set_next(i),kmp(i);    for(int i = 0; i < 4; i ++)        for(int j = 0; j < 4; j++)        {            if(i == j) continue;            if(l[j] > l[i]) continue;            if(strncmp(p[i],p[j],l[j]) == 0) son[i][j] = true;        }    for(int i = 0; i < 4; i ++)    {        son[i][i] = true;        h[i].clear();        for(int j = 0,k; j < 16; j ++)        {            if(j & (1 << i));            else continue;            for(k = 0; k < 4; k ++)                if((j & (1 << k)) && son[i][k] == 0) break;            if(k >= 4) h[i].push_back(j);        }    }    // for(int i = 0; i < 4; i++) for(int j = 0; j < h[i].size(); j ++) printf("I:%d   h:%d\n",i,h[i][j]);}void set_next(int id){    int j = 0,k = -1,len = strlen(p[id]);    next[j] = k;    while(j < len)    {        if(k == -1 |p[id][j] == p[id][k]) j ++,k ++,next[j] = k;        else k = next[k];    }}void kmp(int id){    int i,j,len = strlen(p[id]);    i = j = 0;    while(i < n)    {        if(j == -1 | s[i] == p[id][j]) i ++,j ++;        else j = next[j];        if(j == len) ok[id][i - j] = true;    }    if(j == len) ok[id][i - j] = true;}void solve(){    for(int i = 0; i < n; i ++)        for(int j = 0; j < 16; j ++)            for(int k = 0; k <= m; k ++)                dp[i][j][k][0] = maxn,dp[i][j][k][1] = 0;    dp[0][0][0][0] = dp[0][0][0][1] = 0;    for(int i = 0; i < 4; i ++)        if(ok[i][0]) dp[0][1 << i][l[i]][0] = dp[0][1 << i][l[i]][1] = l[i];    for(int i = 1; i < n; i ++) //position    {        for(int j = 0; j < 16; j ++)        {            for(int k = 0; k < m; k ++)                dp[i][j][k][0] = dp[i - 1][j][k + 1][0],dp[i][j][k][1] = dp[i - 1][j][k + 1][1]; //not insert            dp[i][j][0][0] = min(dp[i][j][0][0],dp[i - 1][j][0][0]);            dp[i][j][0][1] = max(dp[i][j][0][1],dp[i - 1][j][0][1]);        }        for(int j = 0; j < 16; j ++) //used?        {            for(int k = 0; k <= m; k ++) //have benn covered            {                for(int v = 0; v < 4; v ++)                {                    int a = j & (1 << v);                    if(!a && ok[v][i])                    {                        int co = l[v],nco;                        nco = max(k - 1,co);                        if(nco > k - 1 && k) co = nco - k + 1;                        else co = 0;                        if(!k) co = l[v];                        for(int tot = 0; tot < h[v].size(); tot ++)                        {                            dp[i][j | h[v][tot]][nco][0] = min(dp[i][j | h[v][tot]][nco][0],dp[i - 1][j][k][0] + co);                            dp[i][j | h[v][tot]][nco][1] = max(dp[i][j | h[v][tot]][nco][1],dp[i - 1][j][k][1] + co);                        }                    }                }            }        }    }    int mx = 0,mn = maxn;    for(int k = 0; k < m; k ++) mx = max(mx,dp[n - 1][15][k][1]),mn = min(mn,dp[n - 1][15][k][0]);    printf("%d %d\n",mn,mx);}


原创粉丝点击