1. 程式人生 > >【NOIP2001提高組T3】統計單詞個數-字串上的動態規劃

【NOIP2001提高組T3】統計單詞個數-字串上的動態規劃

(本人本題完成於2016-7-19)

題目大意:給定一個字串(長度為20*p,不超過200)和一個包含一些單詞(個數為n,1≤n≤6)的詞典,問如何將該字串分成K(不超過40)份,使得每份中包含的單詞個數之和最大,輸出這個最大值。以一個位置為起始點只能統計一個單詞。

做法:用a[i][j]表示區間(i,j)內所含的單詞個數,可以用暴力計算出所有a[i][j]。再設f[i][j]為字串前i個字元分割成j份的最優解,最終答案即是f[20*p][K]。狀態轉移方程為:f[i][j]=max(f[i][j],f[k][j-1]+a[k+1][i])。

以下是本人程式碼:

#include <cstdio>
#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>usingnamespacestd; long p,K,n,a[210][210]={0},f[210][210]={0}; //a,f的意義如上文所示char w[10][210],s[210]; //w儲存詞典,s儲存待處理的字串bool v[210]={0}; //v[i]表示當前以i為起始位置有沒有統計過單詞,值為1時代表已統計過int main() { scanf("%ld %ld\n",&p,&K);
for(int i=1;i<=p;i++) { for(int j=(i-1)*20+1;j<=i*20;j++) scanf("%c",&s[j]); scanf("\n"); } scanf("%ld\n",&n); for(int i=1;i<=n;i++) { scanf("%s\n",w[i]); for(int j=1;j<i;j++) if (!strcmp(w[i],w[j])) {i--;n--;break;} //比較,如果當前單詞與已輸入單詞重複則捨去當前單詞 }
for(int i=1;i<=20*p;i++) for(int j=i;j<=20*p;j++) { memset(v,0,sizeof(v)); for(int k=1;k<=n;k++) { long len=strlen(w[k]); for(int ii=i;ii<=j-len+1;ii++) { if (v[ii]) continue; bool flag=1; for(int jj=0;jj<len;jj++) if (s[ii+jj]!=w[k][jj]) {flag=0;break;} if (flag) {a[i][j]++;v[ii]=1;} } } } //暴力求出所有a[i][j]for(int k=1;k<=K;k++) for(int i=1;i<=20*p;i++) for(int j=k-1;j<=i-1;j++) //注意從k-1開始,勿漏情況 f[i][k]=max(f[i][k],f[j][k-1]+a[j+1][i]); printf("%ld",f[20*p][K]); return0; }