P1026 统计单词个数
动态规划
先确认区间内的单词个数,由于对于一个单词,首字母不能重叠,所以反向寻找。pre[i][j]表示区间i,j内单词的个数,pre[i][j] = pre[i-1][j],若字符串[i,j]的字串中包含以字符i为首字母的单词,pre[i][j]++
dp[i][j]表示将长度为i的字符串划分j段。枚举断点p,那么dp[i][j] = max(dp[i][j],dp[l][j]+pre[l+1][i]),需要注意的是划分j段至少需要j个字母,所以断点p的位置应从j处开始枚举
#include<stdio.h> #include<algorithm> #include<string.h> #include<stdlib.h> #include<iostream> #include<stack> #include<vector> using namespace std; #define LL long long #define INF 999999999 const LL mod = 1e9+7; string Dic[20]; string temp[20]; string str; int n,k,m; int dp[500][50]; int pre[500][500]; bool Check(int l,int r) { string sub; for(int i=l;i<=r;i++) sub += str[i]; for(int i=1;i<=m;i++) { if(sub.find(Dic[i])==0) return true; } return false; } int main() { cin >> n >> k; for(int i=1;i<=n;i++) { cin >> temp[i]; str += temp[i]; } cin >> m; for(int i=1;i<=m;i++) { cin >> Dic[i]; } int Size = str.size(); for(int i=Size-1;i>=0;i--) { for(int j=i;j>=0;j--) { pre[j+1][i+1] = pre[j+2][i+1]; if(Check(j,i)) pre[j+1][i+1]++; } } dp[0][0] = 0; for(int i=1;i<=k;i++) { dp[i][i] = dp[i-1][i-1]+pre[i][i]; } for(int i=1;i<=Size;i++) dp[i][1] = pre[1][i]; for(int i=1;i<=Size;i++) { for(int j=1;j<=k&&j<i;j++) { for(int p=j;p<i;p++) { dp[i][j] = max(dp[i][j],dp[p][j-1]+pre[p+1][i]); } } } cout << dp[Size][k]<<endl; return 0; }