您的位置:首页 > 其它

重庆市四校联考(南开出题) 解密游戏(Trie树 | | 动态规划)

2016-10-28 12:08 274 查看
【问题描述】

  小南和小开特别喜欢玩解密游戏,轮到小南加密的时候,由于他的加密方式过于丧心病 狂,所以小开怎么也不能解密成功,于是她来找你帮忙。

  密文是一个长度为 n 的数字串,只由 0~9 之间的数字组成。 每个小写字母对应 0~9 之 间的一个数字。小南和小开共同拥有一本字典, 字典中有 m 个单词,每个单词长度不超过50。

  明文是一个数字,表示最少用多少个单词首尾拼接在一起,使得拼接而成的这个字符串可以表示密文(也即相同位置的字符串中字母对应数字跟密文相同)。单词可以重复使用。输出明文,如果无解的话明文为-1。

【输入格式】

  输入文件名为 decrypt.in。

  第一行两个正整数 n,m。

  第二行有 26 个数字,每个数字是 0~9 之间的数,分别表示字母 a~z 对应的数字。

  第三行是长度为 n 的数字串,表示密文。

  接下来 m 行,每行一个小写字母串,表示字典中的一个单词

【输出格式】

  输出文件名为 decrypt.out。

  输出一个整数,表示明文

【输入样例】

10 5

2 2 2 3 3 3 4 4 1 1 5 5 6 6 0 7 0 7 7 8 8 8 9 9 9 0

7325189087

it

your

reality

real

our

【输出样例】

2

【样例解释】

我们最少可以用两个单词 reality our,组成的字符串 realityour 去表示密文。

【数据范围】

对于 30%的数据: 1 ≤ n, m ≤ 1000。

对于 100%的数据: 1 ≤ n, m ≤ 10^5。

题解:

Trie树是什么??不懂,还是用递推吧。
设d[i]为前面长度为i的密码需要的最小单词,最后答案为d[j]
循环找:如果j到i之间这一段可以形成一个单词,那么d[i]=min(d[i],d[j-1]+1)
能不能形成单词可以把所有的单词转换为数字串按字典序排序进行二分查找。
这样一来时间复杂度就只有50*n*log2m了。


代码:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#define maxn 100005
#define oo 2000000005
using namespace std;
struct data
{
char s[55];
friend bool operator <(data a,data b)
{
return strcmp(a.s+1,b.s+1)<0;
}
}a[maxn];
int n,m,d[maxn]={0},vis[30];
char s[maxn];

void in()
{
scanf("%d%d",&n,&m);
for(int i=0;i<26;i++) scanf("%d",&vis[i+'a']);
scanf("%s",s+1);
for(int i=1;i<=m;i++)
{
scanf("%s",a[i].s+1);
int len=strlen(a[i].s+1);
for(int j=1;j<=len;j++)
a[i].s[j]=vis[a[i].s[j]]+'0';
}
sort(a+1,a+m+1);
}

void task()
{
for(int i=1;i<=n;i++) d[i]=oo;

for(int i=1;i<=n;i++)
for(int j=i;j>=i-49&&j>=1;j--) if(d[j-1]+1<d[i])
{
data t;
for(int k=j;k<=i;k++) t.s[k-j+1]=s[k];
t.s[i-j+2]=0;
if(binary_search(a+1,a+m+1,t)) d[i]=min(d[i],d[j-1]+1);
}
if(d
==oo) printf("-1");
else printf("%d",d
);
}

int main()
{
freopen("in.txt","r",stdin);
in();
task();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: