Time Limit: 1 second
Memory Limit: 128 MB
【问题描述】
有一个很长的由小写字母组成字符串。为了便于对这个字符串进行分析,需要将它划分成若干个部分,每个部分称为一个单词。
出于减少分析量的目的,我们希望划分出的单词数越少越好。你就是来完成这一划分工作的。
(原字符串可拆成real+it+your或reality+our,由于reality+our仅为两个部分,因此最优解为2,另外注意,单词列表中的每个单
词都可以重复使用多次,也可以不用)
【输入格式】
从文本文件word.in中读入数据。
第一行,一个字符串。(字符串的长度不超过100)
第二行一个整数n,表示单词的个数。(n<=100)
第3~n+2行,每行列出一个单词。
【输出格式】
一个整数,表示字符串可以被划分成的最少的单词数。
Sample Input
realityour
5
real
reality
it
your
our
Sample Output
2
【题目链接】:http://noi.qz5z.com/viewtask.asp?id=9933
【题解】
记忆化搜搜搞一波;
用f[i][j]表示i..j这个区间里的单词最少能被分成几个单词;(如果为INF表示不合法);
如果i==j;
则判断s[i]在不在字典中;如果在返回1;否则返回INF;
如果i小于j
则判断子串s[i..j]在不在字典中;在的话返回1;
否则枚举断点k,递归划分;
【完整代码】
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <map>
using namespace std;
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
map <string,bool> dic;
string s;
int n;
int f[MAXN][MAXN];
int get_ans(int l,int r)
{
if (f[l][r]!=INF)
return f[l][r];
if (l==r)
if (dic[s.substr(l,1)])
return f[l][r] = 1;
if (dic[s.substr(l,r-l+1)])
return f[l][r] = 1;
for (int i = l;i <= r-1;i++)
f[l][r] = min(f[l][r],get_ans(l,i)+get_ans(i+1,r));
return f[l][r];
}
int main()
{
//freopen("F:\rush.txt","r",stdin);
cin >> s;
cin >> n;
for (int i = 1;i <= n;i++)
{
string temps;
cin >> temps;
dic[temps] = true;
}
memset(f,INF,sizeof(f));
printf("%d
",get_ans(0,s.size()-1));
return 0;
}