题目
明明与可可经常在网上聊天,但最近他们发现父母们可能偷看了他们的隐私谈话,因此他们发明了一些加密语言的方法。
所有合法的单词在给定的单词列表中。一个句子有一些合法单词连续组成(没有空格)。每个单词可以出现任意多次。特殊的加密方法是:每个单词在传送之后,它的字母有可能打乱了重新排列。这次加密的代价定义为:加密前的单词和加密后的单词有多少位置上的字母不相同。如:“abc”变为“abc”,则代价为0;如果变为“acb”、“cba”或“bac”则代价为2;如果变为“bca”或“cab”则代价为3。
对于接收到的句子,解码成加密前的句子可能有多种方案,但明明和可可知道只有句子的加密总代价最小的方案才是真正的原句。面对这么复杂的加密语言,他们的父母当然看不懂。但不幸的是,他们自己也搞不懂了,他们需要你帮助研究。
对于给定的合法单词列表和加密后的句子,求出有合法单词通过加密形成现在句子的最小代价。如果没有可能,则输出-1。
提示:如果一个单词出现多次,每次加密后的单词不一定相同
输入样例
4
one
two
three
there
neotowheret
输出样例
8
样例解释
“one”->“neo” 代价为3;
“two”->“tow” 代价为2;
“three”->“heret”代价为3;
“there”->“heret”代价为5;
最小代价=3+2+3=8.
数据范围
合法单词数:1<=n<=50;每个单词长度:1<=len<=50;句子长度:1<=lens<=100
所有单词和句子中的字符都是小写字母“a”~“z”
题解
动态规划,很容易理解的
设f[i]表示从1到i的句子组成合法句子的最小代价
f[i]=min(f[i],f[i-s]+w)
s为当前单词的长度
w为将加密后的当前单词转换为合法单词的最小代价(可以统计单词中每个字母出现的次数,进行比较)
时间复杂度O(26∗n2∗lenth)
代码
var
n,i,j,k,ans,min:longint;
s:string;
a:array[1..50,1..26]of longint;
t:array[1..50]of string;
function night(b:string;var c:longint):boolean;
var
i,j,e,f,g:longint;
d:array[1..26]of longint;
begin
night:=true;
fillchar(d,sizeof(d),0);
for i:=1 to length(b) do
inc(d[ord(b[i])-96]);
g:=0;
for i:=1 to n do
begin
e:=1;
if length(t[i])<>length(b) then e:=0 else
for j:=1 to 26 do
if a[i,j]<>d[j] then begin e:=0;break;end;
if (e=1) then
begin
f:=0;
g:=1;
for j:=1 to length(t[i]) do
if t[i][j]<>b[j] then inc(f);
if f<c then c:=f;
end;
end;
if g=0 then exit(false);
end;
procedure dfs(k,m:longint);
var
i,j,c:longint;
begin
if (k>length(s))and(m<ans) then begin ans:=m;exit;end;
for j:=min+k-1 to length(s) do
if night(copy(s,k,j-k+1),c) then
begin
dfs(j+1,m+c);
if (j+1>=length(s))and(m+c=5) then
begin
c:=0;
end;
night(copy(s,k,j-k+1),c);
end;
end;
begin
readln(n);
min:=50;
for i:=1 to n do
begin
readln(s);
t[i]:=s;
if length(s)<min then min:=length(s);
for j:=1 to length(s) do
inc(a[i,ord(s[j])-96]);
end;
readln(s);
ans:=1000;
dfs(1,0);
if ans<>1000 then writeln(ans) else writeln(-1);
end.