1. 程式人生 > >統計單詞個數

統計單詞個數

題目描述

給出一個長度不超過200的由小寫英文字母組成的字母串(約定;該字串以每行20個字母的方式輸入,且保證每行一定為20個)。要求將此字母串分成k份(1<k≤40),

且每份中包含的單詞個數加起來總數最大(每份中包含的單詞可以部分重疊。當選用一個單詞之後,其第一個字母不能再用。例如字串this中可包含thisis,選用this之後就不能包含th)。

單詞在給出的一個不超過6個單詞的字典中。

要求輸出最大的個數。

輸入輸出格式

輸入格式:

 

每組的第一行有2個正整數(p,k)

p表示字串的行數,k表示分為k個部分。

接下來的p行,每行均有20個字元。

再接下來有1個正整數s,表示字典中單詞個數。(1s6)

接下來的s行,每行均有1個單詞。

 

輸出格式:

 

1個整數,分別對應每組測試資料的相應結果。

 

完蛋了

想的DP方程太複雜了,根本沒法寫

完蛋惹

 

 

這裡大致就是f[i][j]表示前i個字元,已經有了j個劃分(不是分割線)

用aft[i]表示i往後,以i開頭的單詞最短到哪裡

這樣統計i到j的單詞個數只要找到i到j中aft小於等於j的就可以了

這樣首字母的問題,也很好的解決了

然後這裡j是到了第幾個分塊,而不是第幾個分割線(我的,複雜)這樣直接列舉前一個分塊的末端就可以了

 1 #include<iostream>
 2
#include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 const int maxn=207; 8 const int INF=0x7f7f7f7f; 9 int P,K,s,n,ans; 10 char a[maxn],wrd[7][maxn]; 11 int len[7],aft[maxn],f[maxn][maxn],map[maxn][maxn]; 12 bool vis[maxn];
13 int main(){ 14 //freopen("a.in","r",stdin); 15 memset(f,-INF,sizeof(f)); 16 cin>>P>>K;memset(aft,INF,sizeof(aft)); 17 for(int i=1;i<=P;i++) 18 for(int j=1;j<=20;j++) 19 cin>>a[++n]; 20 cin>>s; 21 for(int i=1;i<=s;i++){ 22 scanf("%s",wrd[i]+1); 23 len[i]=strlen(wrd[i]+1); 24 } 25 for(int u=1;u<=n;u++){ 26 for(int i=1;i<=s;i++){ 27 int v=u+len[i]-1;bool flag=true; 28 for(int k=u;k<=v;k++){ 29 if(a[k]!=wrd[i][k-u+1]) { 30 flag=false;break; 31 } 32 } 33 if(flag) aft[u]=min(aft[u],v); 34 } 35 } 36 f[0][0]=0; 37 for(int i=1;i<=n;i++){ 38 for(int j=i+1;j<=n;j++){ 39 for(int k=i;k<=j;k++){ 40 if(aft[k]<=j) map[i][j]++; 41 } 42 } 43 } 44 for(int i=1;i<=n;i++){ 45 for(int j=1;j<=K;j++){ 46 for(int k=0;k<i;k++){ 47 f[i][j]=max(f[i][j],f[k][j-1]+map[k+1][i]); 48 } 49 } 50 } 51 /*for(int i=1;i<=n;i++){ 52 for(int j=0;j<i;j++){ 53 for(int k=1;k<=K;k++) 54 f[i][k]=max(f[i][k],f[j][k-1]+map[j+1][i]); 55 } 56 } */ 57 cout<<f[n][K]<<endl; 58 return 0; 59 }

真難過

今天下午的狀態太不應該了