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;
}
View Code

 

posted @ 2019-04-29 11:02  声声醉如兰  阅读(204)  评论(0编辑  收藏  举报