题目:
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)(管理员注:这里的不能再用指的是位置,不是字母本身。比如thisis可以算做包含2个is)。
单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。
分析:
用f[i,j]表示前i个字母分成j份所含的单词数,dis[l+1,i]表示从l+1到i位所含的单词数,则状态转移方程为:f[i,j]=max(f[l,j-1]+total[l+1,i])
代码:
const
maxn=200;
var
f:array [0..maxn,0..maxn] of longint;
dis:array [0..maxn,0..maxn] of longint;
flag:array [0..maxn] of boolean;
s1:array [1..10] of string;
n,m,num,temp:longint;
st,s2:string;
function max(a,b:longint):longint;
begin
if a>b then
exit(a)
else
exit(b);
end;
function work(num1,num2:longint):longint;
var
i:longint;
begin
work:=0;
for i:=1 to num do
if (num2-length(s1[i])+1>=num1) and flag[num2-length(s1[i])+1] and(copy(st,num2-length(s1[i])+1,length(s1[i]))=s1[i]) then
begin
inc(work);
flag[num2-length(s1[i])+1]:=false;
end;
end;
function try(num:longint):longint;
var
i:longint;
begin
try:=0;
for i:=1 to num do
if (st[num]=s1[i]) and flag[num] then
begin
flag[num]:=false;
exit(1);
end;
end;
procedure init;
var
i,j,k,l,z:longint;
begin
readln(m);
for z:=1 to m do
begin
fillchar(f,sizeof(f),0);
readln(temp,k);
st:='';
for i:=1 to temp do
begin
readln(s2);
st:=st+s2;
end;
n:=temp*20;
readln(num);
for i:=1 to num do
readln(s1[i]);
for i:=1 to n do
begin
fillchar(flag,sizeof(flag),true);
for j:=i to n do
if i<>j then
dis[i,j]:=dis[i,j-1]+work(i,j)
else
dis[i,j]:=try(j);
end;
for i:=1 to n do
f[i,1]:=dis[1,i];
for i:=2 to n do
for j:=2 to k do
if j<i then
for l:=j to i-1 do
f[i,j]:=max(f[l,j-1]+dis[l+1,i],f[i,j]);
writeln(f[n,k]);
end;
end;
begin
init;
end.