hdu 2296 AC自动机+DP+路径字符串记录(较麻烦)

题意:给出n个字符串,以及每个字符串的权值,求权值最大,字符串长度不超过m,最短且字典序最小的字符串。

//#pragma comment(linker, "/STACK:102400000")
#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<vector>
#define tree int o,int l,int r
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define lo o<<1
#define ro o<<1|1
#define pb push_back
#define mp make_pair
#define ULL unsigned long long
#define LL long long
#define inf 0x7fffffff
#define eps 1e-7
#define N 1009
#define M 26
using namespace std;
int m,n,T,t,x,y,u;
int ch[N][M],v[N],sz;
int f[N],last[N];
char str[109][15];
int d[N][55],pre[N][55],len[N][55];
void init()
{
    sz=1;
    memset(ch[0],0,sizeof(ch[0]));
    memset(v,0,sizeof(v));
    memset(last,0,sizeof(last));
    memset(d,-1,sizeof(d));
    memset(len,0,sizeof(len));
}
int idx(char c)
{
    return c-'a';
}
void insert(char str[],int val)
{
    int u=0;
    for(int i=0; str[i]; i++)
    {
        int c=idx(str[i]);
        if(!ch[u][c])
        {
            memset(ch[sz],0,sizeof(ch[sz]));
            ch[u][c]=sz++;
        }
        u=ch[u][c];
    }
    v[u]+=val;
}
void getac()
{
    f[0]=0;
    queue<int>q;
    for(int c=0; c<M; c++)
    {
        int u=ch[0][c];
        if(u)
        {
            f[u]=0;
            q.push(u);
            last[u]=v[u];/////////////
        }
    }
    while(!q.empty())
    {
        int r=q.front();
        q.pop();
        for(int c=0; c<M; c++)
        {
            int u=ch[r][c];
            if(!u)
            {
                ch[r][c]=ch[f[r]][c];
            }
            else
            {
                q.push(u);
                int s=f[r];
                f[u]=ch[s][c];
                last[u]=v[u]+last[f[u]];//////
            }
        }
    }
}
int dp(int u,int sub)
{
    if(sub==n)return 0;
    int &ans=d[u][sub];
    if(ans!=-1)return ans;
    ans=0;
    for(int i=0; i<M; i++)
    {
        int c=ch[u][i];
        if(last[c]+dp(c,sub+1)>ans)//先保证值最大
        {
            ans=max(ans,last[c]+dp(c,sub+1));
            pre[u][sub]=i;
            if(ans>0)
                len[u][sub]=len[c][sub+1]+1;
        }
        else if (last[c]+dp(c,sub+1)==ans&&len[u][sub]>len[c][sub+1]+1)//再保证长度最短
        {
            pre[u][sub]=i;
            if(ans>0)
                len[u][sub]=len[c][sub+1]+1;
        }
    }
    return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("ex.in","r",stdin);
#endif
    int ncase=0;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=0; i<m; ++i)
            scanf("%s",str[i]);
        for(int i=0; i<m; ++i)
        {
            scanf("%d",&t);
            insert(str[i],t);
        }
        getac();
        dp(0,0);
        int u=0,i=0;
        while(d[u][i]>0)
        {
            printf("%c",pre[u][i]+'a');
            u=ch[u][pre[u][i]];
            i++;
        }
        puts("");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/sbaof/p/3375750.html