Description

著名的考古学家石教授在云梦高原上发现了一处古代城市遗址。让教授欣喜的是在这个他称为冰峰城(Ice-Peak City)的城市中有12块巨大石碑,上面刻着用某种文字书写的资料,他称这种文字为冰峰文。然而当教授试图再次找到冰峰城时,却屡屡无功而返。幸好当时教授把石碑上的文字都拍摄了下来,为了解开冰峰城的秘密,教授和他的助手牛博士开始研究冰峰文,发现冰峰文只有陈述句这一种句型和名词(n)、动词(v)、辅词(a)这三类单词,且其文法很简单: ::= { } ::= ::={ }[ ] ::= | [ ] ::= | [ ] ::= | | 注:其中、和由词典给出,“::=”表示定义为,“|”表示或,{}内的项可以重复任意多次或不出现,[]内的项可以出现一次或不出现。在研究了大量资料后,他们总结了一部冰峰文词典,由于冰峰文恰好有26个字母,为了研究方便,用字母a到z表示它们。冰峰文在句子和句子之间以及单词和单词之间没有任何分隔符,因此划分单词和句子令石教授和牛博士感到非常麻烦,于是他们想到了使用计算机来 帮助解决这个问题。假设你接受了这份工作,你的第一个任务是写一个程序,将一篇冰峰文文章划分为最少的句子,在这个前提下,将文章划分为最少的单词。

Input

输入文件第1行为词典中的单词数n(n<=1000)。输入文件第2行至第(n+1)行每行表示一个单词,形为“a.mot”, a表示词性,可能是n(名词),v(动词),a(辅词)中的一个,mot为单词,单词的长度不超过20。拼写相同而词性不同的单词视为不同的单词,如输入示例中的n.kick与v.kick是两个不同的单词。输入文件第(n+2)行为需要划分的文章,以“.”结束。输入文件中的文章确保为冰峰文。文章是由有限个句子组成的,每个句子只包含有限个单词。文章长度不超过5KB。

Output

输出文件两行,每行一个整数。第1行为划分出来的句子数。输出文件第2行为划分出来的单词数。

Sample Input 1

11
n.table
n.baleine
a.silly
n.snoopy
n.sillysnoopy
v.is
v.isnot
n.kick
v.kick
a.big
v.cry
sillysnoopyisnotbigtablebaleinekicksnoopysillycry.

Sample Output 1

2
9

Hint

为了阅读方便,划分的单词用空格分隔,在单词右标出它的词性,每行写一个句子,用句号表示句子结束。输出对应的划分:sillysnoopy[n] isnot[v] big[a] table[n].baleine[n] kick[v] snoopy[n] silly[a] cry[v].如果用下面的划分:silly[a] snoopy[n] isnot[v] big[a] table[n].baleine[n] kick[v] snoopy[n] silly[a] cry[v].则划分的句子数仍为2个,但单词数却多了1个,为10个,显然应该按前者而不是后者划分。


分析:

做出这道题关键在于理解语法。其中名词短语和动词短语给出的都是递归定义,可以转化为更直观的,

<名词短语> ::= {<辅词>} <名词>,
<动词短语> ::= {<辅词>} <动词>,

也就是以一个名词或动词结尾,前面可以加上任意多个辅词。而句子就是要以名词短语开头,后面的名词短语和动词短语交替出现。

分析出语法结构,就可以进行动态规划。定义词性
j={0,1,2,3}。

\(f[i][0][k]\)表示前i个字母,以i结尾的单词词性为n,构成了k个句子的最小单词数

\(f[i][1][k]\)表示前i个字母,以i结尾的单词词性为v,构成了k个句子的最小单词数

\(f[i][2][k]\)表示前i个字母,以i结尾的单词词性为a,后面该接v了,构成了k个句子的最小单词数

\(f[i][3][k]\)表示前i个字母,以i结尾的单词词性为a,后面该接n了,构成了k个句子的最小单词数

DP状态转移方程


枚举可能以i结尾的单词,设它的词性为type,前一个单词结尾为j。

;

;

;

;


Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<iostream>
#include<queue>
#include<iomanip>
#include<algorithm>
using namespace std;
const int N=1005,M=6010,inf=0x3f3f3f3f;
int n,m,maxlen,word[M][22],f[M][4][2],id;
char s[M];
struct tree
{
    int d[26];
    int op,c;
    void clear()
    {
        memset(d,0,sizeof(d));
        c=-1;op=0;
    }
}a[25010];

void insert(char s[],int op)
{
    int u=0,len=strlen(s),i,v;
    for(i=0;i<len;i++)
    {
        v=s[i]-'a';
        if(a[u].d[v]==0)
        {
            id++;a[id].clear();
            a[u].d[v]=id;
            a[id].c=v;
        }
        u=a[u].d[v];
    }
    a[u].op|=op;
}

int find(int l,int r)
{
    int i,j,u=0,v;
    for(i=l;i<=r;i++)
    {
        v=s[i]-'a';
        if(a[u].d[v]==0) return 0;
        u=a[u].d[v];
    }
    return a[u].op;
}

int main()
{
    int i,j,k,c,p,ans2,ans1;
    char s1[25];
    bool first=true;
    while(~scanf("%d\n",&n))
    {
        if(!first) printf("\n");
        else first=false;
        maxlen=0;
        p=0;id=0;
        a[0].clear();
        memset(word,-1,sizeof(word));
        memset(f,0x3f,sizeof(f));
        for(i=1;i<=n;i++)
        {
            scanf("%s",s1);
            k=strlen(s1);
            maxlen=max(maxlen,k);
            if(s1[0]=='n') insert(s1+2,1);
            else if(s1[0]=='v') insert(s1+2,2);
            else insert(s1+2,4);
        }
        scanf("%s",s+1);
        m=strlen(s+1)-1;
        ans2=inf,ans1=0;
        f[0][0][0]=0;
        p=0;
        for(k=1;k<=m;k++)
        {
            c=p;p=1-p;
            for(i=1;i<=m;i++)
            {
                f[i][0][p]=f[i][1][p]=f[i][2][p]=f[i][3][p]=inf;
                for(j=i-1;j>=i-maxlen&&j>=0;j--)
                {
                    if(word[j+1][i-j]==-1) word[j+1][i-j]=find(j+1,i);
                    int type=word[j+1][i-j];
                    if(type&1)
                    {
                        f[i][0][p]=min(f[i][0][p],f[j][1][p]+1);
                        f[i][0][p]=min(f[i][0][p],f[j][3][p]+1);
                        f[i][0][p]=min(f[i][0][p],f[j][0][c]+1);
                        f[i][0][p]=min(f[i][0][p],f[j][2][c]+1);
                    }
                    if(type&2)
                    {
                        f[i][1][p]=min(f[i][1][p],f[j][0][p]+1);
                        f[i][1][p]=min(f[i][1][p],f[j][2][p]+1);
                    }
                    if(type&4)
                    {
                        f[i][2][p]=min(f[i][2][p],f[j][0][p]+1);
                        f[i][2][p]=min(f[i][2][p],f[j][2][p]+1);
                        f[i][3][p]=min(f[i][3][p],f[j][1][p]+1);
                        f[i][3][p]=min(f[i][3][p],f[j][3][p]+1);
                        f[i][3][p]=min(f[i][3][p],f[j][0][c]+1);
                        f[i][3][p]=min(f[i][3][p],f[j][1][c]+1);
                    }
                }
            }
            ans2=min(f[m][0][p],f[m][1][p]);
            if(ans2!=inf)
            {
                ans1=k;
                break;
            }
        }
        printf("%d\n%d\n",ans1,ans2);
    }
    return 0;
}

hdu4843(NOI2000) 古城之谜 (trie树+DP)的更多相关文章

  1. POJ2004 Mix and build Trie树? dp?

    学习Trie树中,所以上网搜一下Trie树的题,找到这个,人家写着是简单dp,那我就想着能学习到什么Trie树上的dp,但最后发现根本好像跟Trie树没有什么联系嘛... 题意就是给你很多个字符串(长 ...

  2. LA-3942(trie树+dp)

    题意: 给出一个由多个不同单词组成的字典,和一个长字符串,把这个字符串分解成若干个单词的连接,问有多少种方法; 思路: dp[i]表示s[i,L]的方案数,d[i]=∑d[j];s[i,j-1]是一个 ...

  3. NBUT 1222 English Game(trie树+DP)

    [1222] English Game 时间限制: 1000 ms 内存限制: 131072 K 问题描写叙述 This English game is a simple English words ...

  4. Remember the Word,LA3942(Trie树+DP)

    Trie树基础题,记录下代码. #include <cstdio> #include <cstring> #define MaxNode 4005*100 #define No ...

  5. [NOI2000] 古城之谜

    题目描述 给定 n 和 n 个信息,每个信息包含一个词性 a (只有三种:名,动,辅)和对应的词 mot ,形为" \(a.mot\) ".(一次可能多词性) 最后给一个长度不大于 ...

  6. BZOJ1212[HNOI2004]L语言——trie树+DP

    题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...

  7. Codeforces 615C Running Track(DP + Trie树)

    题目大概说给两个串,问最少要用多少个第一个串的子串(可以翻转)拼成第二个串. UVa1401,一个道理..dp[i]表示前缀i拼接成功所需最少的子串,利用第一个串所有子串建立的Trie树往前枚举转移. ...

  8. UVa1401 Remember the Word(DP+Trie树)

    题目给定一个字符串集合有几种方式拼成一个字符串. dp[i]表示stri...strlen-1的方案数 dp[len]=1 dp[i]=∑dp[j](stri...strj-1∈SET) 用集合的字符 ...

  9. 【10.29校内测试】【线段树】【DP】【二进制Trie树求最小值最大】

    Solution 标程太暴力惹QAQ 相当于是26棵线段树的说QAQ 不过我写了另一种写法,从大到小枚举每一个字母,标记字典序在这个字母之上的位置为1,每次都建一棵线段树,维护1的数量,即区间和. 修 ...

随机推荐

  1. 理解 Linux 中 `ls` 的输出

    ls 的输出会因各 Linux 版本变种而略有差异,这里只讨论一般情况下的输出. 下面是来自 man page 关于 ls 的描述: $ man ls ls - list directory cont ...

  2. 『练手』003 Laura.SqlForever如何扩展 兼容更多数据库引擎

     003 Laura.SqlForever如何扩展 兼容更多数据库引擎 数据库引擎插件 在 界面上的体现 导航窗体 的 工具栏 中的 引擎下拉列表        导航窗体 的 树形控件 中的 引擎主节 ...

  3. k8s健康检查(七)--技术流ken

    默认的健康检查 强大的自愈能力是 Kubernetes 这类容器编排引擎的一个重要特性.自愈的默认实现方式是自动重启发生故障的容器.除此之外,用户还可以利用 Liveness 和 Readiness ...

  4. 【带着canvas去流浪(6)】绘制雷达图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...

  5. 将配置文件appsetting中的值转换为动态对象调用

    该文可参考我的另一篇关联文章:   https://www.cnblogs.com/lxhbky/p/6957825.html 配置如下: <!--邀请用户送优惠券规则{邀请人规则:[{邀请人: ...

  6. Django 无名参数与有名参数

    无名参数 配置 urls ,我们需要导入 url 模块,以()定义一个无名的变量 from django.contrib import admin from django.urls import pa ...

  7. 工具资源系列之给虚拟机装个ubantu

    前文我们已经讲解了如何在 mac 系统上安装虚拟机软件,这节我们接着讲解如何利用虚拟机安装 Ubuntu 镜像. 安装镜像的大致步骤基本相同,只不过是配置项略显不同而已,如果需要安装其他系统镜像,请参 ...

  8. Python3 小技巧

    完全个人总接 每个文件头部都可以加入这个,或者放到用单独一个文件,再import *.其实都一样,只需要一行false=False;true=True;none=null=None;hid=lambd ...

  9. FFmpeg部署及相关指令操作说明

    1.首先在http://ffmpeg.zeranoe.com/builds/上下载static版本, 下载好以后解压缩到 c:/ffmpeg/ 2.配置环境变量 path -> c:/ffmpe ...

  10. vue和angular的区别:

    相同: 1.数据绑定:vue和angular绑定都可以用{{}} 2.都支持内置指令和自定义指令 3.都支持内置过滤器和自定义过滤器. 区别: 1.学习成本和API 设计:vue相比于angular来 ...