趣題學演算法之動態規劃-形式語言
阿新 • • 發佈:2019-02-01
/*
題目描述:
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;
}
設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};