题意
间谍通过一些规则吧密信进行了加密。现在需要你对其解密。
加密规则是把密文全部改成小写字母,然后翻转每个单词。并删去空格。
现在给你加密后的文字和字典,要你找出原来的密文。
思路
因为密文的单词是翻转后的,所以我们可以把字典里的单词翻转,存进字典树中。
dp[i]表示i之前是否能组成正确的信息(true)。
dp[j] = dp[i]
当dp[i]为真,并且(i, j-1)能在字典树中找到。
路径还原,其实可以用dp数组来记录路径。
code
#include <bits/stdc++.h>
using namespace std;
int n, m;
char t[10000 + 5];
char w[100000 + 2][1000 + 5];
int dp[10000 + 5];
int pr[10000 + 5];
struct Trie_tree {
int _p;
Trie_tree* _ch[26];
Trie_tree() {
_p = 0;
for (int i=0; i<26; i++) {
_ch[i] = NULL;
}
}
};
Trie_tree* root = new Trie_tree();
void insert (Trie_tree* root, char* p, int c) {
Trie_tree* node = root;
char* s = p;
char tmp;
while (*s) {
tmp = (*s >= 'a') ? (*s) : (*s - 'A' + 'a');
if (node->_ch[tmp - 'a'] == NULL) {
node->_ch[tmp - 'a'] = new Trie_tree();
}
node = node->_ch[tmp - 'a'];
s++;
}
node->_p = c;
}
void dfs(int s) {
if (0 == dp[s]) {
printf("%s", w[pr[s]]);
return ;
}
dfs(dp[s]);
printf(" %s", w[pr[s]]);
}
int main () {
scanf ("%d", &n);
scanf ("%s", t);
scanf ("%d", &m);
for (int i=1; i<=m; i++) {
scanf ("%s", w[i]);// cout << strlen(w[i]) << endl;
reverse(w[i], w[i] + strlen(w[i]));// cout << w[i] << endl;
insert(root, w[i], i);
reverse(w[i], w[i] + strlen(w[i]));
}
memset(dp, -1, sizeof(dp));
dp[0] = 0;
for (int i=0; i<n; i++) {
if (dp[i] == -1) continue;
Trie_tree* node = root;
char *p = t + i;
int _c = 0;
while (*p) {
if (node->_ch[*p - 'a'] == NULL) break;
// cout << *p << endl;
node = node->_ch[*p - 'a'];
p++;
_c++;
// cout << "-_-";
if (node->_p != 0) {
dp[i + _c] = i;
pr[i + _c] = node->_p;
}
}
}
// for (int i=0; i<=n; i++) {
// printf("%d ", dp[i]);
// }
dfs(n); printf("\n");
return 0;
}