【bzoj2121】字符串游戏 【动态规划dp】

题目链接
感觉这个dp还是蛮棒棒的^^
我们让 f[i][j][a][b]=0/1 f [ i ] [ j ] [ a ] [ b ] = 0 / 1 表示大串中i~j的子串与第a个小串1~b的字串是否完全相同, ok[i][j]=0/1 o k [ i ] [ j ] = 0 / 1 表示大串中i~j的子串能否全部拿空, dp[i] d p [ i ] 表示大串前i个字符最少剩下几个。
则有状态转移方程
f[i][j][a][b]|=(f[i][j1][a][b1] and t[j]==s[a][b])||(f[i][k][a][b] and ok[k+1][j])(k=i..j1) f [ i ] [ j ] [ a ] [ b ] | = ( f [ i ] [ j − 1 ] [ a ] [ b − 1 ]   a n d   t [ j ] == s [ a ] [ b ] ) | | ( f [ i ] [ k ] [ a ] [ b ]   a n d   o k [ k + 1 ] [ j ] ) ( k = i . . j − 1 )
ok[i][j]|=f[i][j][a][len[a]] o k [ i ] [ j ] | = f [ i ] [ j ] [ a ] [ l e n [ a ] ]
dp[i]=min(dp[i1]+1,dp[j] and ok[j+1][i]) d p [ i ] = m i n ( d p [ i − 1 ] + 1 , d p [ j ]   a n d   o k [ j + 1 ] [ i ] )
观察发现通过状压可以压掉一维的空间复杂度和时间复杂度。于是就可以乱搞了。

非状压代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int lt,n,ls[35],ok[151][151],f[151][151][31][21],dp[151];
char t[155],s[35][25];
int main(){
    scanf("%s",t+1);
    lt=strlen(t+1);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s[i]+1);
        ls[i]=strlen(s[i]+1);
    }
    for(int i=1;i<=lt;i++){
        for(int j=1;j<=n;j++){
            if(t[i]==s[j][1]){
                f[i][i][j][1]=1;
                ok[i][i]|=f[i][i][j][ls[j]];
            }
        }
    }
    for(int i=lt;i>=1;i--){
        for(int j=i+1;j<=lt;j++){
            for(int a=1;a<=n;a++){
                for(int b=1;b<=ls[a];b++){
                    f[i][j][a][b]|=(f[i][j-1][a][b-1]&&t[j]==s[a][b]);
                    for(int k=i;k<=j-1;k++){
                        f[i][j][a][b]|=(f[i][k][a][b]&&ok[k+1][j]);
                    }
                }
                ok[i][j]|=f[i][j][a][ls[a]];
            }
        }
    }
    for(int i=1;i<=lt;i++){
        dp[i]=dp[i-1]+1;
        for(int j=0;j<i;j++){
            if(ok[j+1][i]){
                dp[i]=min(dp[i],dp[j]);
            }
        }
    }
    printf("%d\n",dp[lt]);
    return 0;
}

状压代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int lt,n,bin[35],ls[35],ok[151][151],f[151][151][31],dp[151];
char t[155],s[35][25];
int main(){
    scanf("%s",t+1);
    lt=strlen(t+1);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s[i]+1);
        ls[i]=strlen(s[i]+1);
    }
    bin[0]=1;
    for(int i=1;i<=30;i++){
        bin[i]=bin[i-1]<<1;
    }
    for(int i=1;i<=lt;i++){
        for(int j=1;j<=n;j++){
            if(t[i]==s[j][1]){
                f[i][i][j]|=bin[1];
                ok[i][i]|=(f[i][i][j]&bin[ls[j]]);
            }
        }
    }
    for(int i=lt;i>=1;i--){
        for(int j=i+1;j<=lt;j++){
            for(int a=1;a<=n;a++){
                for(int b=1;b<=ls[a];b++){
                    f[i][j][a]|=((f[i][j-1][a]&bin[b-1])&&t[j]==s[a][b])*bin[b];
                }
                for(int k=i;k<=j-1;k++){
                    if(ok[k+1][j]){
                        f[i][j][a]|=f[i][k][a];
                    }
                }
                ok[i][j]|=(f[i][j][a]&bin[ls[a]]);
            }
        }
    }
    for(int i=1;i<=lt;i++){
        dp[i]=dp[i-1]+1;
        for(int j=0;j<i;j++){
            if(ok[j+1][i]){
                dp[i]=min(dp[i],dp[j]);
            }
        }
    }
    printf("%d\n",dp[lt]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值