HDOJ-2296 AC自动机+DP..一定要细心..

        构造Trie树..通过Trie树构造AC自动机..再通过AC自动机构造Trie图...

        本题DP的状态为dp[k][p].w 代表当字符串长度为k时..以头节点到p点为后缀的串所能得到的最大权值...同时用dp[k][p].s来存这个k长度的串..状态转移方向为Trie图中有向边的方向..显然k长度的状态只于k-1的状态有关..所以可以用滚动数组来存储dp状态..

        值得注意的是我以前做AC自动机DP时..在更新时没有考虑过用来更新的点在上一层是否有过更新...而本题是一定要考虑的..只有上一层更新过的点才能在当前层更新其沿有向边能到达的点...

        我有一个错误查了很久才解决..以后为了不出错..类似的DP在本层全部点更新完毕后,再来扫描所有点的权值更新ans吧...


贡献两组测试时自己出的数据:

TEST 1:
1
4 2
aa
bb
3 3

ans= aaaa    

TEST 2:
1
49 3
loveufoever
ever
al
12 7 3

ans= aloveufoeveraloveufoeveraloveufoeveraloveufoever

Program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
struct node1
{
       int son[26],fail,w;
}point[1200];
struct node2
{
       string s;
       int w;
}dp[2][1200];
int T,m,n,w[102],i,j,num,h,k,x,len,t,ans;
char s[15];
string str,ans_str;
queue<int> myqueue;
bool used[1200];
bool judge(string a,string b)
{
       int la=a.length(),lb=b.length();
       if (la!=lb) return la>lb;
       return a>b;
}
int main()
{
       freopen("input.txt","r",stdin);
       freopen("output.txt","w",stdout);
       while (!myqueue.empty()) myqueue.pop();
       scanf("%d",&T);
       while (T--)
       {
             scanf("%d%d",&n,&m);
             memset(point,0,sizeof(point));
             num=0;
             for (i=1;i<=m;i++)
             {
                   scanf("%s",s);
                   len=strlen(s);
                   h=0;
                   for (j=0;j<len;j++)
                   {
                         if (!point[h].son[s[j]-'a'])
                              point[h].son[s[j]-'a']=++num;
                         h=point[h].son[s[j]-'a']; 
                   }
                   point[h].w=i;
             }
             memset(w,0,sizeof(w));
             for (i=1;i<=m;i++) scanf("%d",&w[i]);
             for (i=0;i<26;i++)
                if (point[0].son[i]) myqueue.push(point[0].son[i]);
             while (!myqueue.empty())
             {
                   h=myqueue.front();
                   myqueue.pop();
                   point[h].w=w[point[h].w]+point[point[h].fail].w;
                   for (i=0;i<26;i++)
                   {
                          k=point[h].fail;
                          while (k && !point[k].son[i]) k=point[k].fail;
                          point[point[h].son[i]].fail=point[k].son[i];
                          if (point[h].son[i])
                              myqueue.push(point[h].son[i]);
                          else
                              point[h].son[i]=point[k].son[i];
                   }
             }
             k=0;
             for (i=0;i<=num;i++)
             {
                   dp[k][i].w=0;
                   dp[k][i].s="";
             }
             ans=0;  ans_str="";
             while (n--)
             { 
                   k=1-k;
                   for (i=0;i<=num;i++)
                   {
                         dp[k][i].w=0;
                         dp[k][i].s="";
                   }
                   memset(used,false,sizeof(used));
                   used[0]=true;
                   myqueue.push(0);
                   while (!myqueue.empty())
                   {
                         h=myqueue.front();
                         myqueue.pop(); 
                         for (i=0;i<26;i++) 
                         {
                                x=point[h].son[i];
                                if (!used[x])
                                {
                                       used[x]=true;
                                       myqueue.push(x);
                                }
                                if (h && dp[1-k][h].s=="") continue;
                                if (dp[k][x].w>dp[1-k][h].w+point[x].w) continue;
                                str=dp[1-k][h].s+char('a'+i);
                                if (dp[k][x].w<dp[1-k][h].w+point[x].w ||
                                    dp[k][x].s=="" || judge(dp[k][x].s,str))
                                {
                                       dp[k][x].w=dp[1-k][h].w+point[x].w;
                                       dp[k][x].s=str;
                                } 
                         }
                   }
                   for (h=0;h<=num;h++)
                     if (dp[k][h].w>ans || dp[k][h].w==ans && judge(ans_str,dp[k][h].s))
                     {
                             ans=dp[k][h].w;
                             ans_str=dp[k][h].s;
                     }
             } 
          //   printf("%d\n",ans);
             len=ans_str.length();
             for (i=0;i<len;i++) printf("%c",ans_str[i]);
             printf("\n");
       }
       return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值