HDU 2296 Ring(AC自动机+DP)

来源:互联网 发布:淘宝可以卖虚拟物品吗 编辑:程序博客网 时间:2024/05/11 02:14

HDU 2296 Ring(AC自动机+DP)

http://acm.hdu.edu.cn/showproblem.php?pid=2296

题意:

        给你M个单词构成一个词典,每个单词有一个权值(单词出现多次算多个权值),现在要你构造一个不超过长度N的字符串,使得该字符串权值最大。如果出现多个答案,输出最短的,如果依然有多解,输出字典序最小的。

分析:

        本题和之前几题类似。不过注意这题的AC自动机要用match, match[i]表示i节点的后缀单词权值总和.后缀单词指的是:所有可以做i节点表示的串的后缀的单词.

       令dp[i][j]=x表示当前在i点走过了长j的路所生产的最大权值为x. 再用string  path[i][j]来保存那个具有最大权值的最优字符串即可.不过要注意如果最后算的的最大权值是0,那么要输出空串.因为空串最短.

dp[i][j] = max(dp[k][j-1]+match[i]) 若dp[i][j]更新的时候,path[i][j]也要看看是否需要更新成:

if(path[i][j]!=””)path[i][j] =  better(path[i][j] , path[k][j-1]+”x”)x字符表示从k走到i的那条边的字符是x.

初值path=空串,dp[0][0]=0.

注意:做这题的时候出现了几个错误的地方.

首先对于dp[i][j]不可达的节点一定要置-1,不能置1

其次对于当dp[ch[k][j]][len + 1] <dp[k][len] + match[ch[k][j]]时直接替换原来的path,而不是求最优了.

还有HDU提交这题的时候我一直编辑错误,不知道错在哪里?后来不得不改掉一些函数了.后来经过无数次的测试,发现少些了#include<string> .

AC代码:

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<string>using namespace std;int N,M;const int maxnode=1000+100;const int sigma_size=26;inline string better(string a,string b){    if(a=="")        return b;    if(a.size()!=b.size())        return a.size()<b.size() ? a:b;    return a<b? a:b;}struct AC_Automata{    int ch[maxnode][sigma_size];    int match[maxnode];    int f[maxnode];    int sz;    int dp[maxnode][50+10];    string path[maxnode][50+10];    int ans;    string res;    void init()    {        sz=1;        memset(ch[0],0,sizeof(ch[0]));        match[0]=f[0]=0;    }    void insert(char *s,int v)    {        int n=strlen(s),u=0;        for(int i=0;i<n;i++)        {            int id=s[i]-'a';            if(ch[u][id]==0)            {                ch[u][id]=sz;                memset(ch[sz],0,sizeof(ch[sz]));                match[sz++]=0;            }            u=ch[u][id];        }        match[u]=v;    }    void getFail()    {        queue<int> q;        for(int i=0;i<sigma_size;i++)        {            int u=ch[0][i];            if(u)            {                f[u]=0;                q.push(u);            }        }        while(!q.empty())        {            int r=q.front();q.pop();            for(int i=0;i<sigma_size;i++)            {                int u=ch[r][i];                if(!u){ ch[r][i]=ch[f[r]][i]; continue; }                q.push(u);                int v=f[r];                while(v && ch[v][i]==0) v=f[v];                f[u]=ch[v][i];                match[u] += match[f[u]];            }        }    }    void solve()    {        ans=0;        res="";        for(int i=0;i<sz;i++)            for(int j=0;j<=N;j++)            {                dp[i][j]=-1;                path[i][j]="";            }        dp[0][0]=0;        for(int len=0;len<N;len++)//当前走的长度            for(int k=0;k<sz;k++)if(dp[k][len]!=-1)//当前所在的节点            {                for(int j=0;j<sigma_size;j++)//下一步走的方向                    if(dp[ch[k][j]][len+1] <= dp[k][len]+match[ch[k][j]])                    {                        char temp='a'+j;                        if(dp[ch[k][j]][len+1] < dp[k][len]+match[ch[k][j]])                        {                            dp[ch[k][j]][len+1] = dp[k][len]+match[ch[k][j]];                            path[ch[k][j]][len+1] = path[k][len]+temp;                        }                        else                        {                            path[ch[k][j]][len+1] = better(path[ch[k][j]][len+1],path[k][len]+temp);                        }                        if(ans < dp[ch[k][j]][len+1])                        {                            ans = dp[ch[k][j]][len+1];                            res = path[ch[k][j]][len+1];                        }                        else if(ans == dp[ch[k][j]][len+1])                            res = better(res,path[ch[k][j]][len+1]);                    }            }    }}ac;char str[100+10][10+5];int val[100+10];int main(){    int T;    scanf("%d",&T);    while(T--)    {        ac.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",&val[i]);            ac.insert(str[i],val[i]);        }        ac.getFail();        ac.solve();        if(ac.ans==0)            printf("\n");        else            cout<<ac.res<<endl;    }    return 0;}


0 0
原创粉丝点击