/*
题目描述:
X大学的P教授,在研究机器语言的过程中提出了一个自己定义的小规模语言L.
A'是一个有限字母集,包含大小写字母
W'是一个单词集合,其中每个单词均有字母表A中的字母组成。
现在需要我们设计一个程序:若有关文本P,以及单词词汇集T(T中的每个字母都属于P),求T中能顺序连接(这里的连接指的是并集)构成P的最少单词数.
例子如下:
P:ABCDEFA
T:A B C D AB BCD EF DE EFA
分析:
T中的AB BCD EFA顺序连接构成P;且是最少的.
*/
/*分析:
一段文本P针对单词集T,可以划分成不同的单词序列(可能有多个解),
每个序列均对应一个长度(每个解对应一个目标值),计算单词划分的最短长度,
(计算最优值)
将文本P[1..n]中的第i个字符到第j个字符的部分记为P[i..j],考虑P[i..j]的最小单词划分,
记为S(i,j),S(i,j)中的所有单词顺序连接成P[i..j],是满足这两个条件的含有单词数最小的集合
本题的最优子问题结构可以描述为:
设P[k+1..j]是划分该S(i,j)中的最后一个单词,则在S(i,j)中去除最后一个单词后得到的部分为S(i,k)
是P[i..k]的一个最优单词划分
设f[i,j]为S(i,j)所含单词个数,根据最优子结构,得到
1':当i>j f[i,j]=0;
2':当i<=j且P[i,j]中没有单词 f[i,j]=无穷;
3':当i<=j min(i<=k<=j且P[k+1..j]为单词){f[i,k]+1};
*/
#include
<iostream>
#include
<set>
#include
<sstream>
#include
<string>
#include
<sstream>
#include
<cstring>
using
namespace
std;
const
int MAXN
=
500;
const
int INT_MAX
=
0x3f3f3f3f;
int
findMin(
const string P,set
<string
>
&T){
int r,q,i,j,l,k;
int f[MAXN][MAXN];
int n
=P.
length();
// f=new int[(n+1)*(n+1)];
memset(f,
0,
sizeof(f));
// fill(f,f+(n+1)*(n+1),0);
for(l
=
1;l
<=n;l
++){
//表示单词序列的子链长
for(i
=
1;i
<=n
-l
+
1;i
++){
//单词序列的左端点
int length
=l;
j
=i
+l
-
1;
//单词序列的右端点
q
=INT_MAX;
for(k
=i
-
1;k
<j;k
++){
//由于下标的关系,等价于i<=k<=j;
if(T.
find(P.
substr(k,length
--))
!=T.
end())
//判断P[k+1..j]是否为一个单词集合T中的单词
if(q
>f[i][k]
+
1)
q
=f[i][k]
+
1;
}
f[i][j]
=q;
}
}
r
=f[
1][n];
return r;
}
int
main(){
int n,result;
string s;
cin
>>n;
getline(cin,s,
'
\n
');
for(
int i
=
0;i
<n;i
++){
string P,t;
set
<string
> T;
getline(cin,P,
'
\n
');
getline(cin,t,
'
\n
');
istringstream s1(t);
while(s1
>>t)
T.
insert(t);
result
=
findMin(P,T);
if(result
>P.
length()){
cout
<<
"Error"
<<endl;
}
else{
cout
<<result
<<endl;
}
}
return
0;
}