wikioi-天梯-普及一等-划分dp-1040:统计单词个数

给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)(管理员注:这里的不能再用指的是位置,不是字母本身。比如thisis可以算做包含2个is)。
单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。

第一行为一个正整数(0<n<=5)表示有n组测试数据
每组的第一行有二个正整数(p,k)
p表示字串的行数;
k表示分为k个部分。
接下来的p行,每行均有20个字符。
再接下来有一个正整数s,表示字典中单词个数。(1<=s<=6)
接下来的s行,每行均有一个单词。

每行一个整数,分别对应每组测试数据的相应结果。


1
1 3
thisisabookyouareaoh
4
is
a
ok
sab

7

this/isabookyoua/reaoh

类型:dp  难度:2

题意:给出一个字符串,以及一个有s个词的字典,将这个字符串分成k份,求如何分词总数最大。字符串中,两个词不能从同一个位置开启,但是可以在同一个位置结束。即this和th只能算一个,但是this和is算两个。

分析:首先需要统计字符串中词的个数和位置,我的方法是,用len[i]记录从i开始的词的最小长度(因为两个词不能从一个位置开始,所以从一个位置开始的词只能取一个,显然,取的词越短越不会受划分的影响,越容易得到更多的词)。

然后,用划分dp解决,用dp[pos][k]表示将字符串从pos位置开始到结尾这段子串,划分成k份能得到的最大词数。

递推方程:dp[pos][k] = mmax(cnt+dp[i+1][k-1]),其中i为本次划分的位置,cnt为[pos,i]这段子串包含的单词数,dp[0][k]

代码如下:

#include<iostream>
#include<cstring>
#include<string>
using namespace std;

int len[210],dp[210][210];
string sen;

int mmin(int a,int b)
{
    if(a<0) return b;
    if(b<0) return a;
    return (a<b)?a:b;
}

int mmax(int a,int b)
{
    return (a>b)?a:b;
}

int fun(int pos,int k)
{
    if(pos<0 || k<=0) return 0;
    if(dp[pos][k]>0) return dp[pos][k];
    
    int endcnt[210],cnt = 0;
    memset(endcnt,0,sizeof(endcnt));
    
    for(int i=pos; i<=sen.length()-k; i++)
    {
        if(len[i]>0)
            endcnt[i+len[i]-1]++;
        cnt += endcnt[i];
        dp[pos][k] = mmax(dp[pos][k],cnt+fun(i+1,k-1));
    }
    return dp[pos][k];
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        memset(len,-1,sizeof(len));
        memset(dp,0,sizeof(dp));
        
        int p,k;
        cin>>p>>k;
        string tmp;
        while(p--)
        {
            cin>>tmp;
            sen += tmp;
        }
        
        int s;
        cin>>s;
        while(s--)
        {
            string word;
            cin>>word;
            for(int i=0; i<=sen.length()-word.length(); i++)
            {
                string sub(sen.substr(i,word.length()));
                if(word == sub)
                    len[i] = mmin(len[i],word.length());
            }
        }
        cout<<fun(0,k)<<endl;
    }
}


 

你可能感兴趣的:(dp,WIKIOI,天梯)