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. 把ABP框架部署到Docker中

    本文旨在将Abp项目部署到Docker容器中,借助Gitee存储,Jenkins持续构建,利用Docker Compose生成镜像.启动镜像,在官网给定的Abp项目中,虽然用到了Dockerfile. ...

  2. 补习系列(1)-springboot项目基础搭建课

    目录 前言 一.基础结构 二.添加代码 三.应用配置 四.日志配置 五.打包部署 小结 前言 springboot 最近火的不行,目前几乎已经是 spring 家族最耀眼的项目了.抛开微服务.技术社区 ...

  3. 2.4配置的热更新「深入浅出ASP.NET Core系列」

    希望给你3-5分钟的碎片化学习,可能是坐地铁.等公交,积少成多,水滴石穿,谢谢关注. 大家知道通常我们修改网站的配置文件比如,webconfig的时候,网站需要重启才能读取到最新的修改,所谓热更新就是 ...

  4. 基本 SQL 之增删改查(一)

    上篇文章,我们介绍了数据的基本 DDL 语句,你应当具备基本的创建数据库.数据表的 SQL 语句,以及表字段的基本数据类型的熟知. 那么本篇就来总结总结大家日常最频繁接触到的 DDM 语句,也就是基本 ...

  5. Redis在Windows中安装方法

    首先下载Redis 下载地址:https://github.com/MSOpenTech/redis/releases Redis支持32位和64位,这个需要根据你系统平台的实际情况选择,我的是64位 ...

  6. PLSQL 登录出现 ora12638 credential retrieval failed

    参考:http://blog.csdn.net/yjq8116/article/details/4203168 解决了 开始 -> 程序 -> Oracle -> Configura ...

  7. python基础之逻辑运算符

    python逻辑运算符: ①and ‘与’ 总结: 如果and左边为False,则直接返回左边的结果(False) 如果and左边为True,则返回的结果取决于右边的数值 ②or ‘或’ 总结: 如果 ...

  8. Excel的读取和保存(POI)

    示例 Excel文件: 数据读取: 保存路径: Jar包准备 下载地址: 链接:https://pan.baidu.com/s/1RZAwEsFwjKMlnYYGwHMfaA 提取码:h9mj 文件上 ...

  9. 五一出门必备的手机APP神器 让你瞬间大开眼界

    如今我们手机上有各种各样的软件,但是比较实用的又有哪些呢?所以每次大家都会花上很久的时间去查找满意的软件吧!今天就给大家送上一波福利,因为五一小长假就要到来了,说不定大家会使用到呢! 轻颜相机 轻颜相 ...

  10. Android 注解框架对比

    Java的注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,标记可以加在包,类,属性,方法,本地变量上.然后你可以写一个注解处理器去解析处理这些注解(人称编译时注解 ...