题意:有 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; }