原题来自:ACM Pacific NW Region 1998
Description
给出一些数字串,判断是否有一个数字串是另一个串的前缀。
Input
输入数据为多组数据,每组数据读到 9 时结束。
Output
对于每组数据,如果不存在一个数字串是另一个串的前缀,输出一行 Set t is immediately decodable
,否则输出一行 Set t 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
数字串只包含 0,1,记每个数字串长度为 1 <= l <= 10,则 。每组数据至少有 2 个数字串,至多有 8 个数字串。
字典树的小模板题
类似于 Phone List 例题一,只需要将输入改动再加个结束条件即可
这里把例题一的CODE也放上:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t,ch[100005][10],bo[100005],tot;
char s[105];
bool insert(char *s) {
int u=1,len=strlen(s),flag=0;
for (int i = 0; i < len; i ++) {
int c = s[i]-'0';
if (!ch[u][c]) ch[u][c] = ++tot;
else if (i==len-1) flag = 1;
u = ch[u][c];
if (bo[u]) flag=1;
}
bo[u] = 1;
return flag;
}
signed main() {
cin >> t;
while (t--) {
tot = 1;
int n,ans=0;cin >> n;
memset(ch,0,sizeof(ch));
memset(bo,0,sizeof(bo));
while (n--) {
cin >> s;
if (insert(s)) ans = 1;
}
if (!ans) cout << "YES\n";
else cout << "NO\n";
}
return 0;
}
本题 CODE :
#include <bits/stdc++.h>
using namespace std;
int t,ch[1000005][5],bo[1000005],tot;
char s[100005];
bool insert(char *s) {
int u = 1,len = strlen(s),flag = 0;
for (int i = 0; i < len; i ++) {
int c = s[i]-'0';
if (!ch[u][c]) ch[u][c] = ++ tot;
else if (i == len-1) flag = 1;
u = ch[u][c];
if (bo[u]) flag = 1;
}
bo[u] = 1;
return flag;
}
signed main() {
while (scanf("%s",s) != EOF) {
memset(ch,0,sizeof(ch));
memset(bo,0,sizeof(bo));
t ++;
tot = 1;
bool f = 0;
insert(s);
// cout << s << endl;
while(cin >> s && s[0] != '9') {
// cout << s << endl;
if (insert(s)) f = 1;
}
if (!f) cout << "Set " << t << " is immediately decodable";
else cout << "Set " << t << " is not immediately decodable";
puts("");
}
return 0;
}
代码解说 :
数据结构
-
Trie树:使用二维数组
ch
实现,ch[u][c]
表示节点u
的子节点c
的编号。 -
bo数组:标记节点是否为某个字符串的结尾。
-
变量:
-
t
:测试用例编号。 -
tot
:动态分配的节点总数,初始根节点为1。 -
ch
和bo
数组在每次测试前重置,清空Trie。
-
核心函数 insert
-
功能:将字符串插入Trie树,并检查是否存在前缀冲突。
-
逻辑:
-
从根节点(
u=1
)开始遍历字符串。 -
对每个字符:
-
若当前字符的子节点不存在,则创建新节点。
-
若当前字符是最后一个字符且子节点已存在,说明存在更长的字符串(当前字符串是前缀),标记冲突。
-
若路径中存在已结束的节点(
bo[u]
为真),说明当前字符串包含更短的前缀字符串,标记冲突。
-
-
最后标记当前字符串的结束节点,返回冲突标志。
-
主函数逻辑
-
循环处理多个测试用例,直到输入结束(EOF)。
-
初始化:每个测试用例重置Trie,计数器
t
自增。 -
读取字符串:
-
第一个字符串直接插入。
-
后续字符串通过循环读取,直到遇到以
'9'
开头的字符串结束输入。
-
-
冲突检测:若任何字符串插入时检测到冲突,标记集合为不可解码。
-
输出结果:根据冲突标记判断并输出当前集合是否即时可解码。