zoukankan      html  css  js  c++  java
  • 洛谷 P1026 统计单词个数 区间DP

    题目描述

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

    单词在给出的一个不超过6个单词的字典中。

    要求输出最大的个数。

    输入输出格式

    输入格式:

    每组的第一行有二个正整数(p,k)

    p表示字串的行数;

    k表示分为k个部分。

    接下来的p行,每行均有20个字符。

    再接下来有一个正整数s,表示字典中单词个数。(1<=s<=6)

    接下来的s行,每行均有一个单词。

    输出格式:

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

    输入输出样例

    输入样例#1:
    1 3
    thisisabookyouareaoh
    4
    is
    a
    ok
    sab
    
    输出样例#1:
    7
    

    方法挺直接的,先求出每一段字符串包含了多少单词,再求出将整个字符串分割成 m 段最多可以获得多少单词。

    dp[i][j]  表示前 i 个字符组成的串,分割成 j 段,最多能获得多少单词。

    dp[i][j] = max(dp[k][j-1] + wordNum[k+1][length])   (j-1 <= k <= length-1)

    代码:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    const int MAX = 205;
    const int INF = 0x3fffffff;
    
    int wordNum[MAX][MAX];        //i 到 j 这一段包括了多少个单词
    int dp[MAX][MAX];        //剩下的 i 串,分成 j 段最多包含多少单词 
    string s;
    string words[10];
    int l, m, n;
    
    int dfs(int i, int j);        //枚举 
    
    int main(){
    //    freopen("input.txt", "r", stdin);
        cin >> l >> m;
        s = "";
        while(l--){
            string t;
            cin >> t;
            s += t;
        }
        
        cin >> n;
        for(int i=1; i<=n; i++){
            cin >> words[i];
        }
        
        //求出 dp 数组
        memset(wordNum, 0, sizeof(wordNum));
        for(int len = 1; len <=s.length(); len++){
            for(int i=0; i+len-1<s.length(); i++){
                int j = i + len - 1;
                bool hasWord = false;
                for(int x=1; x<=n; x++){        //从最左边的字符开始能不能构成一个单词 
                    string t = words[x];
                    int p = i, q = 0;
                    while(p <= j && q < words[x].length()){
                        if(s[p] != words[x][q])
                            break;
                        p++;  q++;
                    }
                    if(q >= words[x].length()){
                        hasWord = true;
                        break;
                    }
                }
                wordNum[i][j] = wordNum[i+1][j] + hasWord;    //能够成就加一 
            }
        }
        
        memset(dp, 0, sizeof(dp));
        for(int i=0; i<s.length(); i++){
            dp[i][1] = wordNum[0][i];
        }
        for(int j=2; j<=m; j++){                    //分割成 j 段 
            for(int i=0; i<s.length(); i++){        //有 i 个字符 
                for(int k=j-2; k<i; k++){                //分割点
                    dp[i][j] = max(dp[i][j], dp[k][j-1] + wordNum[k+1][i]);
                }
            }
        }
        
        cout << dp[s.length()-1][m];
        
        return 0;
    }
  • 相关阅读:
    《网络对抗》 后门原理与实践
    《网络对抗》 逆向及Bof进阶实践
    20145211黄志远《网络对抗》Exp9 Web安全基础实践
    20145211 《网络对抗》Exp8 Web基础
    20145211黄志远 《网络对抗》Exp7 网络欺诈技术防范
    20145211MSF基础应用实验
    20145211黄志远 《网络对抗技术》 恶意代码分析
    20145211黄志远 《网络对抗技术》 免杀原理与实践
    20145211黄志远 《网络对抗技术》 后门原理与实践
    20145211《网络对抗》注入Shellcode并执行&&Return-to-libc攻击
  • 原文地址:https://www.cnblogs.com/lighter-blog/p/7400392.html
Copyright © 2011-2022 走看看