题意:
ZJM 收到了 Q老师 送来的生日礼物,但是被 Q老师 加密了。只有 ZJM 能够回答对 Q老师 的问题,Q老师 才会把密码告诉 ZJM。
Q老师 给了 ZJM 一些仅有 01 组成的二进制编码串, 他问 ZJM:是否存在一个串是另一个串的前缀.
Input
多组数据。每组数据中包含多个仅有01组成的字符串,以一个9作为该组数据结束的标志。
Output
对于第 k 组数据(从1开始标号),如果不存在一个字符串使另一个的前缀,输出"Set k is immediately decodable",否则输出"Set k is not immediately decodable"。
每组数据的输出单独一行
Sample Input
01
10
0010
0000
9
01
10
010
0000
9
Sample Output
Set 1 is immediately decodable
Set 2 is not immediately decodable
思路:
这道题可以采用字典树的方式求解,对于输入的字符串将新的字符串插入到字典树中。题目要求判断是否存在某个字符串是其他字符串的前缀,这个我们在插入的过程中判断即可,有两种情况,一种是当前正在插入的字符串是已经插进去的字符串的前缀,另一种是存在已经插入的字符串是当前字符串的前缀。
对于第一种我们在插入的过程中,一直插到最后,看最后一个位置的是否已经存在,若是已经存在,那么这个字符串就是之前某字符串的前缀;对于第二种,我们判断插入的过程中是否有某个位置的字符串中止标志为1,代表这个位置是某个字符串的终止位置,那么那个字符串就是当前字符串的前缀。
代码:
#include<iostream>
#include<string.h>
#include<string>
using namespace std;
struct Trie
{
static const int N = 1010, charset = 2;
//最多有1010个节点,每个节点有0和1两个孩子
int tot;//用来表示当前是哪个节点
int root;//整个字典树的根
int child[N][charset]; //代表N节点的某个孩子节点是多少
int flag[N]; //用来判断某个节点是一个完整字符串的终点节点
Trie() {
memset(child, -1, sizeof(child));
tot = 0;
root = 0;
}
void clear() {
memset(child, -1, sizeof(child));
tot = 0;
root = 0;
}
int insert(string str)
{
int now = root;
int judge = -1;
int len = str.size();
for (int i = 0; i < len; i++)
{
int x = str[i] - '0';
if (child[now][x] == -1)
{
child[now][x] = ++tot;
flag[tot] = 0;
}
else
{
if (i == len - 1 || flag[child[now][x]])judge = 1;
}
now = child[now][x];
}
flag[now] = 1;//到达了末尾
return judge;
}
};
int main()
{
string str;
Trie trie;
int num = 1;
bool judge = false;
while (cin >> str)
{
if (str != "9")
{
if(trie.insert(str) == 1)judge = true;
}
else
{
if (!judge)cout << "Set " << num << " is immediately decodable" << endl;
else cout << "Set " << num << " is not immediately decodable" << endl;
num++;
judge = false;
trie.clear();
}
}
}