字典树初级

来源:互联网 发布:ubuntu设置用户根目录 编辑:程序博客网 时间:2024/06/15 21:09

题目链接

题意:给一个字符串,求组成这个字符串的期望最大,字串有自己的权值。

题解:

考虑动态规划。从一个点出发可以检查后面每一个可能的单词的权值,然后更新它的后继状态。可以用 map 或者 trie 来维护(map 可能需要适当优化,否则很容易超时)。有几个小技巧:

  • 最后回溯的时候,只要在每一个走过的地方打一个点,然后从左往右一个一个字符输出,碰到点就输个空格就好了。
  • 使用 map 的注意优化:单词长度不超过 30。这样的话超过 30 的单词直接认为权值是 0 就好了。
我是用字典树写得。DP很简单,主要是刚学字典树,也就是把每一个字符串存到树中,并给他一个权值。查询的时候就会特别快,我觉得应该就是O(len)吧。详解可以看大白208页,讲的不错。。下面给代码
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<math.h>#include<iostream>#include<algorithm>#include<stack>#include<queue>#include<vector>#include<set>#include<map>#include<string>using namespace std;typedef long long ll;const int INF=0x3f3f3f3f;int n,m,cnt;char str[5010];double value[200010],dp[200010];int g[200010][30],pre[200010];void Insert(){    int k=0;scanf("%s",str);    int len=strlen(str);    for(int i=0;i<len;i++)    {        int c=str[i]-(str[i]>='a'?'a':'A');        if(!g[k][c])        {g[k][c]=++cnt;value[cnt]=0;memset(g[cnt],0,sizeof(g[cnt]));}        k=g[k][c];    }    scanf("%lf",&value[k]);value[k]=len*len*log(value[k]);}void print(int len){    if(len==0)return;    print(pre[len]);    if(pre[len])printf(" ");    for(int i=pre[len]+1;i<=len;i++)printf("%c",str[i]);}int main(){    while(scanf("%d",&n)!=EOF)    {        int cnt=0;value[0]=0;        memset(g[0],0,sizeof(g[0]));        for(int i=1;i<=n;i++)            Insert();        scanf("%d",&m);        while(m--)        {            memset(dp,0,sizeof(dp));            scanf("%s",str+1);            int len=strlen(str+1);            for(int i=1;i<=len;i++)            {                int rt=0;                for(int j=0;j<30;j++)                {                    if(!str[i+j])continue;                    int c=str[i+j]-(str[i+j]>='a'?'a':'A');                    if(!g[rt][c])                    {                        if(dp[i+j]<dp[i-1])                        {                            dp[i+j]=dp[i-1];                            pre[i+j]=i-1;                        }                        break;                    }                    else                    {                        rt=g[rt][c];                        if(dp[i+j]<dp[i-1]+value[rt])                        {                            dp[i+j]=dp[i-1]+value[rt];                            pre[i+j]=i-1;                        }                    }                }            }            printf("%lf\n",dp[len]);print(len);printf("\n");        }    }    return 0;}


原创粉丝点击