洛谷P1026 统计单词个数【区间dp】

醉酒当歌 提交于 2020-03-03 08:42:29

题目https://www.luogu.org/problemnew/show/P1026

题意:

给定一个字符串,要求把他分成k段。给定s个单词,问划分成k段之后每段中包含的单词和最大是多少。

一个位置作为单词的开头只能计算一次。

思路:

如果仅仅是统计某一个区间内的最大单词数,这比较简单。每次从后往前推一个字符,如果这个字符是一个单词的开头,那么$cnt[i][j] = cnt[i+1][j]+1$

但是现在要分成$j$段,这是状态之一,另一个状态应该是已经考虑前$i$个字符。

也就是用$dp[i][j]$表示前$i$个字符划分成$j$段的最大单词数。

很显然$dp[i][j] = dp[d][j-1] + cnt[d +1][i]$,也就是说在$0~i$之间找到一个位置$d$,从这里断开,前面的组成$j-1$段,后面的作为一个新的段。

需要考虑的是,一个只有$i$个字符的字符串,最多只能划分成$i$段。

并且要注意当$j =1$时需要特殊处理。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<map>
 4 #include<set>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<cmath> 
 9 #include<stack>
10 #include<queue>
11 #include<iostream>
12 
13 #define inf 0x7fffffff
14 using namespace std;
15 typedef long long LL;
16 typedef pair<string, string> pr;
17 
18 int p, k, s;
19 const int maxn = 205;
20 string str;
21 string word[10];
22 int cnt[maxn][maxn];
23 int dp[maxn][maxn];
24 
25 int main()
26 {
27     scanf("%d%d", &p, &k);
28     for(int i = 0; i < p; i++){
29         string tmp;
30         cin>>tmp;
31         str += tmp;
32     }
33     scanf("%d", &s);
34     for(int i = 1; i <= s; i++){
35         cin>>word[i];
36     }
37     
38     int len = str.length();
39     
40     for(int i = len - 1; i >= 0; i--){
41         for(int j = i; j >= 0; j--){
42             for(int x = 1; x <= s; x++){
43                 int l = word[x].length();
44                 if(str.substr(j, min(i - j + 1, l)) == word[x]){
45                     cnt[j][i] = cnt[j + 1][i] + 1;
46                     break;
47                 }
48                 else cnt[j][i] = cnt[j + 1][i];
49                 //cout<<str.substr(j, min(i - j + 1, l))<<" "<<cnt[j][i]<<endl; 
50             }
51             
52         }
53     }
54     
55     for(int i = 1; i <= k; i++){
56         dp[i][i] = dp[i - 1][i - 1] + cnt[i][i];
57     }
58     for(int i = 0; i < len; i++){
59         dp[i][1] = cnt[0][i];
60         for(int j = 2; j <= min(k, i); j++){
61             for(int d = j - 1; d < i; d++){
62                 dp[i][j] = max(dp[i][j], dp[d][j - 1] + cnt[d + 1][i]);
63             }
64         }
65     }
66     
67     printf("%d\n", dp[len - 1][k]);
68     
69     return 0; 
70 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!