EOJ 1018 单词的划分 DP/STL

题目描述

有一个很长的由小写字母组成字符串。为了便于对这个字符串进行分析,需要将它划分成若干个部分,每个部分称为一个单词。

出于减少分析量的目的,我们希望划分出的单词数越少越好。你就是来完成这一划分工作的。

输入格式

第一行为一整数 T,表示有 T 组测试数据。

每组测试数据第一行为一字符串。(长度小于 256)

第二行为一整数 N。(1<=N<=100)

以下 N 行,每行一个单词,每个单词长度小于 128。

输出格式

每组测试数据占一行 , 这一行只有一个整数,表示字符串可以被划分成的最少的单词数。我们保证单词是可划分的。

样例

input

1
realityour
5
real
reality
it
your
our

output

2

思路:遍历字符串,寻找以当前字母结尾时的子串所能拆分的最少单词数,转移方程:dp[i] = min(dp[i], dp[i-word.length()]+1) ,注意处理各种边界条件。实现的过程中用map建立了一个哈希表,将每个单词的最后一个字母作为索引,将所有单词整理成wordlist方便查找。代码实现如下:

#include <iostream>
#include <string>
#include <map>
#include <vector>

using namespace std;

int main()
{
    int T;
    cin>>T;
    for(int t=0; t<T; ++t){
        int dp[300] = {0};
        int w_cnt;
        string st;
        map<char, vector<string> > wordhash;//哈希表
        cin>>st>>w_cnt;
        for(int i=0; i<w_cnt; ++i){
            string w;
            char key;
            cin>>w;
            key = w[w.length()-1];//单词的最后一个字母作为索引
            /*建哈希表*/
            if(wordhash.count(key) == 0){
                vector<string> wordlist;
                wordlist.push_back(w);
                wordhash.insert({key, wordlist});
            }
            else{
                map<char, vector<string> >::iterator it = wordhash.find(key);
                it->second.push_back(w);
            }
            /*建哈希表*/
        }
        for(int i=0; i<st.length(); ++i){//遍历字符串
            char &key = st[i];//获取当前字母
            if(wordhash.count(key) == 0){//若不存在当前字母结尾的单词
                dp[i] = i>0 ? dp[i-1] : 0;//则能拆分的单词数不变
            }
            else{
                vector<string> &wordlist = wordhash[key];
                for(int j=0; j<wordlist.size(); ++j){//遍历以该字母结尾的单词的wordlist
                    string &word = wordlist[j];
                    if(i+1>=word.length()){
                        string sub = st.substr(i+1-word.length(),word.length());
                        if(word == sub){//若当前单词匹配当前子串
                            if(i<word.length())//若该子串在句首
                                dp[i] = 1;
                            else{//否则更新为最少拆分的情况
                                dp[i] = dp[i]==0 ? dp[i-word.length()]+1 : min(dp[i], dp[i-word.length()]+1);
                            }
                        }
                    }
                }
            }
        }
        cout<<dp[st.length()-1]<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值