题意:有 N (N <= 50000)个单词(每个单词长度不超过50),问组成长度不超过100的目标串最少要用多少个单词。
题目链接:http://poj.org/problem?id=1732
——>>状态:dp[i] 表示组成前 i 个字符所要用的最少单词数
状态转移方程:dp[i + wLen - 1] = min(dp[i + wLen - 1], dp[i - 1] + 1)
注:单词可以重复使用。。
#include <cstdio>
#include <cstring>
#include <algorithm>
const int MAXN = 50000 + 10;
const int MAXW = 50 + 10;
const int MAXT = 100 + 10;
const int INF = 0x3f3f3f3f;
const char *h = "22233344115566070778889990";
int N;
char s[MAXT];
char word[MAXN][MAXW], buf[MAXN][MAXW];
int dp[MAXT];
int path[MAXT];
bool first;
void Read()
{
scanf("%d", &N);
for (int i = 0; i < N; ++i)
{
scanf("%s", word[i]);
}
}
void Init()
{
for (int i = 0; i < N; ++i)
{
for (int j = 0; word[i][j] != '\0'; ++j)
{
buf[i][j] = h[word[i][j] - 'a'];
}
}
memset(dp, 0x3f, sizeof(dp));
first = true;
}
void Dp()
{
int len = strlen(s);
for (int i = 0; i < len; ++i)
{
for (int j = 0; j < N; ++j)
{
int wLen = strlen(buf[j]);
if (i + wLen - 1 < len && strncmp(&s[i], buf[j], wLen) == 0)
{
if (i == 0)
{
dp[i + wLen - 1] = 1;
path[i + wLen - 1] = j;
}
else if (dp[i - 1] + 1 < dp[i + wLen - 1])
{
dp[i + wLen - 1] = dp[i - 1] + 1;
path[i + wLen - 1] = j;
}
}
}
}
}
void DfsPrint(int pos)
{
if (pos == -1) return;
DfsPrint(pos - strlen(word[path[pos]]));
if (first)
{
first = false;
}
else
{
printf(" ");
}
printf("%s", word[path[pos]]);
}
void Output()
{
int len = strlen(s);
if (dp[len - 1] == INF)
{
puts("No solution.");
}
else
{
DfsPrint(len - 1);
puts("");
}
}
int main()
{
while (scanf("%s", s) == 1)
{
Read();
Init();
Dp();
Output();
}
return 0;
}