hdu2296-(AC自动机+DP)

本文介绍了一种结合AC自动机和动态规划(DP)的算法实现方案,用于解决特定字符串匹配问题。通过构建AC自动机来高效地匹配多个模式串,并使用DP算法寻找最优路径。文章详细解释了算法流程,包括AC自动机的构建、失败指针的设置及DP状态转移过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题解:将字符串都放在AC自动机上然后看一下到达每个位置能增加多少权值,最后转移的时候跟根据权值大小,字典序大小更新一下即可.dp一维表示长度,二维表示到达哪个结点,一开始把所有的结点初始化成-表示不可能到达该结点dp[0][0]=0。转移方程看下面代码


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int mx = 1e3+5;
int n,m;
struct node{
    char s[55];
    int len;
    int w;
    bool operator<(const node &a)const{
        return strcmp(s,a.s)<0;
    }
    void operator=(const node &a){
        for(int i = 0; i < a.len; i++)
            s[i] = a.s[i];
        len = a.len;
        w = a.w;
    }
};
struct tried{
    int ch[mx][26];
    int f[mx];
    int v[mx];
    node dp[55][mx];
    int sz;
    void init(){
        memset(ch[0],0,sizeof(ch[0]));
        memset(dp,0,sizeof(dp));
        memset(v,0,sizeof(v));
        memset(f,0,sizeof(f));
        sz = 1;
    }
    int idx(char c){
        return c-'a';
    }
    void insert(char *s,int w){
        int u = 0;
        int len = strlen(s);
        for(int i = 0; i < len; i++){
            int d = idx(s[i]);
            if(!ch[u][d]){
                memset(ch[sz],0,sizeof(ch[sz]));
                ch[u][d] = sz++;
            }
            u = ch[u][d];
        }
        v[u] = w;
    }
    void getfail(){
        queue<int>q;
        int u = 0;
        for(int d = 0; d < 26; d++)
            if(ch[u][d])
                q.push(ch[u][d]);
        while(!q.empty()){
            u = q.front();
            q.pop();
            v[u]+=v[f[u]];
            for(int d = 0; d < 26; d++){
                if(!ch[u][d]){
                    ch[u][d] = ch[f[u]][d];
                    continue;
                }
                int ret = ch[u][d];
                f[ret] = ch[f[u]][d];
                q.push(ret);
            }
        }
    }
    void work(){
        for(int i = 0; i <= n; i++)
            for(int j = 0; j < sz; j++)
                dp[i][j].w = -1;
        dp[0][0].w = 0;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < sz; j++)
                if(dp[i][j].w!=-1)
                for(int k = 0; k < 26; k++){
                    int ret = ch[j][k];
                    if(dp[i][j].w+v[ret]>dp[i+1][ret].w){
                        dp[i+1][ret] = dp[i][j];
                        dp[i+1][ret].s[dp[i+1][ret].len++] = 'a'+k;
                        dp[i+1][ret].w = dp[i][j].w+v[ret];
                    }
                    else if(dp[i][j].w+v[ret]==dp[i+1][ret].w&&dp[i][j]<dp[i+1][ret]){
                        dp[i+1][ret] = dp[i][j];
                        dp[i+1][ret].s[dp[i+1][ret].len++] = 'a'+k;
                        dp[i+1][ret].w = dp[i][j].w+v[ret];
                    }
                }
        node ans = dp[0][0];
        for(int i = 1; i <= n; i++)
            for(int j = 0; j < sz; j++)
                if(dp[i][j].w>ans.w)
                    ans = dp[i][j];
                else if(dp[i][j].w==ans.w&&dp[i][j]<ans)
                    ans = dp[i][j];
        ans.s[ans.len] = 0;
        puts(ans.s);
    }
}word;
char s[mx][20];
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        word.init();
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= m; i++)
            scanf("%s",s[i]);
        for(int i = 1; i <= m; i++){
            int w;
            scanf("%d",&w);
            word.insert(s[i],w);
        }
        word.getfail();
        word.work();
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值