题目链接

算法:划分型DP

PS:被卡过3天。日期:2013-10-10 ~ 2013-10-12 18:52:48

这题是我提交了13次AC= =汗= =

题目描述:

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

注意:

1、此题和【wikioi】1017 乘积最大  的性质差不多,都是划分k份(1017是添乘号,其实就是分k+1份)

2、唯一不同的是,判断单词是一个整体,少一个就不能加入,所以要特别注意

3、此题预处理恶心,就是在主DP前还要DP一个二维数组a,a[i][j]表示下标i->j单词数(恶心就恶心在更新这里,我是看了别人的题解的= =)

首先是主方程DP:

我们用F[n][k]来表示0到n(因为是字符串,我用string存的)划分成k份得到的数最大

得到:

F[i][1] = a[1][i]  (0 <= i < str.size())

F[i][k] = max(F[i][k], A[j+1][i]*F[j][k-1]) (k-1 <= j < i, 2 <= k <= m) //m是要分成的份数

//想想为什么是k-1而不是k? 因为是分成k份,相当于有k-1个乘号

for(int l = 2; l <= k; l++)
for(int i = l-1; i < str.size(); i++)
for(int j = i-1; j >= l-1; j--)
f[i][l] = max(f[i][l], f[j][l-1] + a[j+1][i]);

然后到初始化a数组的DP:

我们从字符串屁股找起(j=str.size()-1  -> 0),每一次设i从j到0更新a[i][j]

很容易得到方程

a[i][j] = a[i+1][j] + 1 (以i为下标找到一个单词(必须以i为单词的第一个下标))

a[i][j] = a[i+1][j]       (以i为下标找不到单词,就等于i+1->j的单词数)

//dic是存单词的,str是整个字符串
int yes, i, j, l;
for(j = str.size()-1; j >= 0; j--)
for(i = j; i >= 0; i--)
{
for(l = 0; l < s; l++)
{
yes = 0;
//其实就是看str[j]到i后面是否加了新单词,加了就直接退出(即使有相同的串,更何况不相同的了)
if(str.find(dic[l], i) == i && dic[l].size() <= j-i+1) yes = 1; //如果以i开头找到新单词
/* //也可以这样
if(str[i] == dic[l][0] && dic[l].size() <= j-i+1)
{
yes = 1;
for(int p = 0; p < dic[l].size(); p++)
if(str[i+p] != dic[l][p])
{
yes = 0; break;
}
}
*/
if(yes) break;
}
if(yes) a[i][j] = a[i+1][j]+1;
else a[i][j] = a[i+1][j];
}

总结:

1、贪心策略用错:

错:判断是否有前缀,有前缀就跳过。(贪心,因为有了前缀的话,应该用短的,将长的去掉)

正解:不需要此贪心,在dp中已包含

2、一直认为是某个点错,没考虑是整体错误

3、被数据坑得以为对,一直提交

以后多多注意= =

放上全部代码:

#include <iostream>
#include <string>
#include <cstring>
using namespace std; string str, dic[6];
bool cdic[6][6], used[6];
int a[210][210], f[210][40], k, s; void chu() //初始化a数组,a[i][j]表示下标i->j单词数
{
memset(a, 0, sizeof(a));
int yes, i, j, l;
for(j = str.size()-1; j >= 0; j--)
for(i = j; i >= 0; i--)
{
for(l = 0; l < s; l++)
{
yes = 0;
//其实就是看str[j]到i后面是否加了新单词,加了就直接退出(即使有相同的串,更何况不相同的了)
if(str.find(dic[l], i) == i && dic[l].size() <= j-i+1) yes = 1; //如果以i开头找到新单词
/* //也可以这样
if(str[i] == dic[l][0] && dic[l].size() <= j-i+1)
{
yes = 1;
for(int p = 0; p < dic[l].size(); p++)
if(str[i+p] != dic[l][p])
{
yes = 0; break;
}
}
*/
if(yes) break;
}
if(yes) a[i][j] = a[i+1][j]+1;
else a[i][j] = a[i+1][j];
}
} void dp()
{
memset(f, 0, sizeof(f));
for(int i = 0; i < str.size(); i++)
f[i][1] = a[0][i];
for(int l = 2; l <= k; l++)
for(int i = l-1; i < str.size(); i++)
for(int j = i-1; j >= l-1; j--)
f[i][l] = max(f[i][l], f[j][l-1] + a[j+1][i]);
} void print()
{
cout << f[str.size()-1][k] << endl;
} void init()
{
string temp;
int n, p;
cin >> n;
while(n--)
{
cin >> p >> k;
str = "";
while(p--)
{
cin >> temp; str += temp;
}
cin >> s;
for(int i = 0; i < s; i++)
cin >> dic[i];
chu();
dp();
print(); }
} int main()
{
init();
return 0;
}

【wikioi】1040 统计单词个数的更多相关文章

  1. Codevs 1040 统计单词个数

    1040 统计单词个数 2001年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 给出一个长度不超过200的 ...

  2. Codevs_1040_[NOIP2001]_统计单词个数_(划分型动态规划)

    描述 http://codevs.cn/problem/1040/ 与Codevs_1017_乘积最大很像,都是划分型dp. 给出一个字符串和几个单词,要求将字符串划分成k段,在每一段中求共有多少单词 ...

  3. codevs1040统计单词个数(区间+划分型dp)

    1040 统计单词个数 2001年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold   题目描述 Description 给出一个长度不超 ...

  4. 第六章 第一个Linux驱动程序:统计单词个数

    现在进入了实战阶段,使用统计单词个数的实例让我们了解开发和测试Linux驱动程序的完整过程.第一个Linux驱动程序是统计单词个数. 这个Linux驱动程序没有访问硬件,而是利用设备文件作为介质与应用 ...

  5. 第六章第一个linux个程序:统计单词个数

    第六章第一个linux个程序:统计单词个数 从本章就开始激动人心的时刻——实战,去慢慢揭开linux神秘的面纱.本章的实例是统计一片文章或者一段文字中的单词个数.  第 1 步:建立 Linu x 驱 ...

  6. NOIP200107统计单词个数

    NOIP200107统计单词个数 难度级别: A: 编程语言:不限:运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 给出一个长度不超过200的由 ...

  7. NOIP2001 统计单词个数

    题三 统计单词个数(30分) 问题描述 给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个).要求将此字母串分成k份(1<k&l ...

  8. luogu P1026 统计单词个数

    题目链接 luogu P1026 统计单词个数 题解 贪心的预处理母本串从i到j的最大单词数 然后dp[i][j] 表示从前i个切了k次最优解 转移显然 代码 #include<cstdio&g ...

  9. P1026 统计单词个数——substr

    P1026 统计单词个数 string 基本操作: substr(x,y) x是起始位置,y是长度: 返回的是这一段字符串: 先预处理sum[i][j],表示以i开头,最多的单词数: 从后往前寻找,保 ...

随机推荐

  1. protobuf-net 对象二进制序列化与反序列号(转)

    概述: Protobuf是google开源的一个项目,用户数据序列化反序列化,google声称google的数据通信都是用该序列化方法.它比xml格式要少的多,甚至比二进制数据格式也小的多. Prot ...

  2. php开发(TP框架使用)

    由于最近玩了PHP,我向来有个原则,学一门服务端语言至少得玩两个框架,前段时间用PHP写了些demo+小项目,看见身边有人在使用TP,于是乎鼓捣学习学习.如何学,无非也就是做个小demo:就目前看来现 ...

  3. phpcms-v9系统搭建wap网站及单页面

    如需要绑定域名为wap.domain.com,作下如操作: 一.把wap.domain.com域名绑定到你的这个网站主机上. 二.在网站后台——模块——手机门户域名里面填写“http://wap.do ...

  4. phpcms v9网站搬家更换域名的方法

    PHPCMS 是国内领先的网站管理系统,同时也是一个开源的PHP开发框架. 本文介绍phpcms v9网站搬家更换域名的方法. 1.在新的主机空间把phpcms安装好. 新安装的版本一定要和准备搬迁的 ...

  5. hdu 4023 2011上海赛区网络赛C 贪心+模拟

    以为是贪心,结果不是,2333 贪心最后对自己绝对有利的情况 点我 #include<cstdio> #include<iostream> #include<algori ...

  6. hibernate 关联映射

    关联关系大致分为两大类: 1.单向关系:只需单向访问关联端.例如:只能通过老师访问学生,或者只能通过学生访问老师. 2.双向关系:关联的两端可以互相访问.例如:老师和学生之间可以互相访问. 单向关联可 ...

  7. eclipse中快捷键

    转为大写  ctrl+shift+x 转为小写  ctrl+shift+y 根据类名快速找到类文件 ctrl+shift+r 返回上一级 ALT  +  <- 速定位到某一行 ctrl+L

  8. hdu 3001(状压dp, 3进制)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 由于本题中一个点最多能够访问2次,由此可以联想到3进制; visited[i][j]表示在状态i ...

  9. 使用python做科学计算

    这里总结一个guide,主要针对刚开始做数据挖掘和数据分析的同学 说道统计分析工具你一定想到像excel,spss,sas,matlab以及R语言.R语言是这里面比较火的,它的强项是强大的绘图功能以及 ...

  10. 《数据结构与算法分析》学习笔记(五)——二叉树

    (一)查找二叉树ADT 1.二叉查找树ADT性质:     对于树中的每个节点X,它的左子树中所有关键字值都小于X的关键字值,而它的右子树值的关键字值都大于X的关键字值. 2.一些ADT的基本操作 结 ...