HDU2296 Ring AC自动机+DP

来源:互联网 发布:方正卡通字体优化 编辑:程序博客网 时间:2024/06/10 07:00

题目链接:点击打开链接



题目大意:有m个关键字,每个关键字有一个权值,让构造出一个长度不大于n的目标串,使得该目标串的权值尽可能大。对于相同的权值的多个目标串,我们需要输出长度最小的一组,存在多个长度相同的目标串时输出字典序最小的一组。


分析:构造出tire树,对于树中的每一个节点我们看做为一个状态,定义dp(i,j)为前i个字符在状态j时的最大权值,string s(i,j)为该状态下的目标串。


实现代码如下:

#include <cstdio>#include <iostream>#include <cstring>#include <queue>#include <algorithm>using namespace std;#define INF 0x7fffffff#define son_num 26#define maxl 55#define maxn 1010int w[maxn];  //纪录每个关键字的权值int dp[maxl][maxn];    //dp[i][j]纪录长度为i的字符串在状态j时的最大总值char s[maxl][maxn][maxl];  //s[i][j]纪录在该状态下的字典序最小的序列bool cmp(char *s1,char *s2){    int len1=strlen(s1);    int len2=strlen(s2);    if(len1!=len2)        return len1<len2;    return strcmp(s1,s2)<0;}struct node{    int next[maxn][son_num];    int fail[maxn];    int terminal[maxn];  //纪录每一个关键字的编号    int root,size;    int newnode()    {        for(int i=0;i<son_num;i++)  next[size][i]=-1;        terminal[size++]=-1;        return size-1;    }    void init()    {        size=0;        root=newnode();    }    void insert(char *str,int id)    {        int p=root;        int i=0;        while(str[i])        {            int index=str[i]-'a';            if(next[p][index]==-1)              next[p][index]=newnode();            p=next[p][index];            i++;        }        terminal[p]=id;    }    void build_fail()    {        queue <int> que;        fail[root]=root;        for(int i=0;i<son_num;i++)        {            if(next[root][i]==-1)              next[root][i]=root;            else            {                fail[ next[root][i] ]=root;                que.push(next[root][i]);            }        }        while(!que.empty())        {            int p=que.front();            que.pop();            for(int i=0;i<son_num;i++)            {                if(next[p][i]==-1)                  next[p][i]=next[ fail[p] ][i];                else                {                    fail[ next[p][i] ]=next[ fail[p] ][i];                    que.push(next[p][i]);                }            }        }    }    void solve(int n)    {        for(int i=0;i<=n;i++)          for(int j=0;j<size;j++)            dp[i][j]=-INF;        dp[0][0]=0;        char ans[maxl],tmp[maxl];        int maxa=0;        memset(s[0][0],0,sizeof(s[0][0]));        memset(ans,0,sizeof(ans));        for(int i=0;i<n;i++)          for(int j=0;j<size;j++)            if(dp[i][j]>=0)            {                strcpy(tmp,s[i][j]);                int len=strlen(tmp);                for(int k=0;k<son_num;k++)                {                    int cnt=next[j][k];                    tmp[len]=k+'a';                    tmp[len+1]='\0';                    int cnt_dp=dp[i][j];                    if(terminal[cnt]!=-1) cnt_dp+=w[ terminal[cnt] ];                    if(dp[i+1][cnt]<cnt_dp||(dp[i+1][cnt]==cnt_dp&&cmp(tmp,s[i+1][cnt])))                    {                        dp[i+1][cnt]=cnt_dp;                        strcpy(s[i+1][cnt],tmp);                        if(cnt_dp>maxa||(cnt_dp==maxa&&cmp(tmp,ans)))                        {                            maxa=cnt_dp;                            strcpy(ans,tmp);                        }                    }                }            }        printf("%s\n",ans);    }}AC;int main(){    char str[maxl];    int n,x,t;    scanf("%d",&t);    while(t--)    {        AC.init();        scanf("%d%d",&n,&x);        for(int i=0;i<x;i++)        {            scanf("%s",str);            AC.insert(str,i);        }        for(int i=0;i<x;i++)          scanf("%d",&w[i]);        AC.build_fail();        AC.solve(n);    }    return 0;}


0 0