Time Limit: 10 Sec Memory Limit: 162 MB
Description
标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的。现在你要处理的就是一段没有标点的文章。 一段文章T是由若干小写字母构成。一个单词W也是由若干小写字母构成。一个字典D是若干个单词的集合。 我们称一段文章T在某个字典D下是可以被理解的,是指如果文章T可以被分成若干部分,且每一个部分都是字典D中的单词。 例如字典D中包括单词{‘is’, ‘name’, ‘what’, ‘your’},则文章‘whatisyourname’是在字典D下可以被理解的 因为它可以分成4个单词:‘what’, ‘is’, ‘your’, ‘name’,且每个单词都属于字典D,而文章‘whatisyouname’ 在字典D下不能被理解,但可以在字典D’=D+{‘you’}下被理解。这段文章的一个前缀‘whatis’,也可以在字典D下被理解 而且是在字典D下能够被理解的最长的前缀。 给定一个字典D,你的程序需要判断若干段文章在字典D下是否能够被理解。 并给出其在字典D下能够被理解的最长前缀的位置。
Input
输入文件第一行是两个正整数n和m,表示字典D中有n个单词,且有m段文章需要被处理。 之后的n行每行描述一个单词,再之后的m行每行描述一段文章。 其中1<=n, m<=20,每个单词长度不超过10,每段文章长度不超过1M。
Output
对于输入的每一段文章,你需要输出这段文章在字典D可以被理解的最长前缀的位置。
题目分析:
整体思路:Trie树+ 暴力 DP
d
p
[
i
]
dp[i]
dp[i]表示文章中长度为i的前缀是否能被理解
将每个单词插入Trie树
并将所有单词长度记录于length数组并升序排序
对于每个文章,初始时
d
p
[
0
]
=
1
dp[0]=1
dp[0]=1
从文章的第
l
e
n
g
t
h
[
1
]
−
1
length[1]-1
length[1]−1位开始匹配 (即前面留出至少一个单词的空位)
假设当前匹配的位置为i
对于所有
l
e
n
g
t
h
[
j
]
(
1
<
j
<
n
)
length[j]( 1< j < n)
length[j](1<j<n)
若
d
p
[
i
−
l
e
n
g
t
h
[
j
]
+
1
]
=
=
t
r
u
e
dp[i-length[j]+1]==true
dp[i−length[j]+1]==true
那么就查询从文章中
i
−
l
e
n
g
t
h
[
j
]
+
1
i-length[j]+1
i−length[j]+1~
i
i
i位的字符串是否在Trie中出现过
出现过则更新答案
匹配中遇到
i
−
l
e
n
g
t
h
[
j
]
+
1
<
0
i-length[j]+1<0
i−length[j]+1<0 则说明单词长度超过了当前匹配的位置
由于排了序,接下来的单词也都超出长度,所以直接跳出循环
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return x*f;
}
struct node
{
node* nxt[26];
int judge;
node(){for(int i=0;i<26;++i)nxt[i]=NULL; judge=0;}
};
node* rt=new node();
int n,m;
char pt[20],txt[1000010];
int length[50];
int dp[1000010];
void ins(char *ss,int len)
{
node *p=rt;
for(int i=0;i<len;++i)
{
int x=ss[i]-'a';
if(p->nxt[x]==NULL) { node* k=new node(); p->nxt[x]=k;}
p=p->nxt[x];
}
p->judge=1;
}
int find(int ll,int rr)
{
node* p=rt;
for(int i=ll;i<=rr;++i)
{
int x=txt[i]-'a';
p=p->nxt[x];
if(p==NULL) return 0;
}
if(p->judge) return 1;
else return 0;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)
{
scanf("%s",&pt);
int len=strlen(pt);
ins(pt,len);//插入Trie
length[i]=len;
}
sort(length+1,length+1+n);//将单词长度升序排序
while(m--)
{
scanf("%s",&txt);
memset(dp,0,sizeof(dp)); dp[0]=1;//记得初始化
int len=strlen(txt),ans=0;
for(int i=length[1]-1;i<len;++i)//要从length[1]-1位开始
{
for(int j=1;j<=n;++j)
{
int num=i-length[j]+1;
if(num<0) break;//单词长度超出匹配范围直接退出
if(!dp[num]||length[j]==length[j-1])continue;
//相同长度不再匹配
if(find(num,i)) dp[i+1]=1,ans=i+1;//匹配成功则更新
}
}
printf("%d\n",ans);
}
return 0;
}