趣题学算法之动态规划-形式语言

/*
题目描述:
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;
}

猜你喜欢

转载自blog.csdn.net/zyf2695421695/article/details/77977508
今日推荐