hdu2296 AC自动机

本文介绍如何使用AC自动机解决字符串匹配问题,通过构建自动机并优化字符串选择,确保在相同分数的情况下选择最短且字典序最小的字符串。

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

    AC自动机水题,随便写写就过了,注意记录最优的字符串,保证同等分值情况下最短,长度相同的时候字典序最小就行了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define N 1100
#define Max 26
typedef long long LL;
using namespace std;
struct node
{
    int id,num;
    node *next[Max],*fail;
} tree[N],*root;
int cnt;
int val[105];
node* newnode()
{
    for(int i = 0; i<Max; i++) tree[cnt].next[i] = NULL;
    tree[cnt].fail = NULL;
    tree[cnt].num = 0;
    tree[cnt].id = cnt;
    return &tree[cnt++];
}
void insert(char *str,int x)
{
    int i=0,s;
    node *t=root;
    while(str[i])
    {
        s=str[i]-'a';
        if(t->next[s]==NULL)
            t->next[s]=newnode();
        t=t->next[s];
        i++;
    }
    t->num = val[x];
}
void build_ac_automation()
{
    queue<node *>q;
    node *tmp=root;
    q.push(tmp);
    while(!q.empty())
    {
        tmp=q.front();
        q.pop();
        for(int i=0; i<Max; i++)
            if(tmp->next[i]==NULL)
            {
                if(tmp==root)tmp->next[i]=root;
                else tmp->next[i]=tmp->fail->next[i];
            }
            else
            {
                if(tmp==root)tmp->next[i]->fail=root;
                else
                {
                    tmp->next[i]->fail=tmp->fail->next[i];
                    tmp->next[i]->num+=tmp->fail->next[i]->num;
                }
                q.push(tmp->next[i]);
            }
    }
}
char s[105][20];
int dp[55][N];
string str[55][N];
int main()
{
    int t,n,m,i,j,k;
    scanf("%d",&t);
    while(t--)
    {
        cnt = 0;
        root = newnode();
        scanf("%d%d",&n,&m);
        for(i = 1; i<=m; i++)scanf("%s",s[i]);
        for(i = 1; i<=m; i++)
        {
            scanf("%d",&val[i]);
            insert(s[i],i);
        }
        build_ac_automation();
        memset(dp,-1,sizeof(dp));
        dp[0][0] = 0;
        str[0][0] = "";
        for(i = 0; i<n; i++)
        {
            for(j = 0;j<cnt;j++)
            {
                if(dp[i][j] == -1)continue;
                dp[i+1][j] = dp[i][j];
                str[i+1][j] = str[i][j];
            }
            for(j = 0; j<cnt; j++)
            {
                if(dp[i][j] == -1)continue;
                for(k = 0; k<26; k++)
                {
                    int v = tree[j].next[k]->id;
                    int tmp = tree[j].next[k]->num;
                    if(dp[i][j]+tmp>dp[i+1][v])
                    {
                        dp[i+1][v] = dp[i][j]+tmp;
                        str[i+1][v] = str[i][j]+(char)('a'+k);
                    }
                    else if(dp[i][j]+tmp == dp[i+1][v])
                    {
                        string nstr = str[i][j]+(char)('a'+k);
                        if(nstr.length()<str[i+1][v].length())
                            str[i+1][v] = nstr;
                        else if(nstr.length() == str[i+1][v].length())
                            if(nstr<str[i+1][v])
                                str[i+1][v] = nstr;
                    }
                }
            }
        }
        int ans = 0;
        string astr;
        for(i = 0; i<cnt; i++)
        {
            if(dp[n][i]>ans)
            {
                ans = dp[n][i];
                astr = str[n][i];
            }
            else if(dp[n][i] == ans)
            {
                if(str[n][i].length()<astr.length())
                    astr = str[n][i];
                else if(astr.length() == str[n][i].length())
                    if(astr>str[n][i])
                        astr = str[n][i];
            }
        }
        cout<<astr<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值