ZOJ: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1387
POJ: http://poj.org/problem?id=1432
題目大意:
給出一個字母的譯碼錶,給出一個有n個單詞的字典,給出一串編碼。問再給出字典中有多少種不同的解碼方式。
題目分析:
首先編碼只有-和.,可以很方便地建立一棵Trie樹,還是最熟悉的二叉方式。
typedef struct trie
{
int count; //單詞數
struct trie *dot, *dash;
}trie;
之後將每一個讀入的單詞插到Trie樹上。
用動態規劃處理 Morse sequence, 下面記爲str。
記f[i]爲第i個字符到strlen(str)-1的不同解碼數,f[i]=sum(f[i+j]*count[k], 表示從i開始的j位可以解碼爲一個單詞,且相同編碼的單詞有count[k]個),具體的count和單詞的匹配用之前建立的Trie樹完成。
源代碼:
Trie樹的寫法根據看到的一個感覺不錯的版本修改過。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define maxn 10010
#define maxlen 20010
const char* morse[26] = {
".-", "-...", "-.-.", "-..",
".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..",
"--", "-.", "---", ".--.",
"--.-", ".-.", "...", "-",
"..-", "...-", ".--", "-..-",
"-.--", "--.."
};
typedef struct trie
{
int count; //單詞數
struct trie *dot, *dash;
}trie;
trie *trie_new()
{
trie *t = (trie *)malloc(sizeof(trie));
t->dot = t->dash = NULL;
t->count = 0;
return t;
}
void trie_add(trie *root, const char code[])
{
int p=0, len=strlen(code);
trie *node=root;
while (p<len)
{
if (code[p]=='.')
{
if (!node->dot)
node->dot = trie_new();
node = node->dot;
}
else
{
if (!node->dash)
node->dash = trie_new();
node = node->dash;
}
p++;
}
node->count++;
}
void trie_free(trie *p)
{
if (p)
{
trie_free(p->dot);
trie_free(p->dash);
free(p);
}
}
void getmorse(const char word[], char code[])
{
int j=0;
for (int i=0; i<strlen(word); i++)
{
int mlen=strlen(morse[word[i]-'A']);
for (int k=0; k<mlen; k++, j++)
code[j]=morse[word[i]-'A'][k];
}
code[j]='\0';
}
void init(char str[], trie *root)
{
int n;
char word[maxlen], code[maxlen];
scanf("%s", str);
scanf("%d", &n);
for (int i=0; i<n; i++)
{
scanf("%s", word);
getmorse(word, code);
trie_add(root, code);
}
}
int dp(const char str[], trie *root)
{
int f[maxn];
int slen=strlen(str);
f[slen]=1;
for (int i=slen-1; i>=0; i--)
{
f[i]=0;
trie *p=root;
for (int j=i; j<slen; j++)
{
if (str[j]=='.')
{
if (p->dot==NULL) break;
p=p->dot;
}
else
{
if (p->dash==NULL) break;
p=p->dash;
}
if (p->count!=0) f[i] += (p->count)*f[j+1];
}
}
return f[0];
}
int main()
{
char str[maxlen];
int cs, ans;
trie *root;
scanf("%d", &cs);
while (cs--)
{
trie_free(root);
root = trie_new();
init(str, root);
ans = dp(str, root);
printf("%d\n", ans);
}
return 0;
}