1. 程式人生 > >趣題學演算法之動態規劃-形式語言

趣題學演算法之動態規劃-形式語言

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