【字典树入门】hdu 1305 Immediate Decodability

HDU 1305 Immediate Decodability

  • 题意:一组01字符串,问是否存在一个字符串是另一个字符串的前缀。

  • 两种方法

  • 一:在沿途经过节点打标记,最后依次在终点询问 cnt[p]>=2

  • 缺点:需要额外的空间储存输入的字符串,容易内存超限
  • 二:(更优方法)在叶子节点打标记,沿途询问 cnt[p] 以及在终点询问 son[p][0] || son[p][1] 。不用额外储存。
  • 思路:对01串建Trie,在建的过程中即可维护答案。
  • 在插入结点时,若某结点是已有01串末尾结点,那该串一定有前缀。
  • 或者在插入该串的末尾时,该结点是已有数字串的中间结点,那该串一定是某已有串的前缀。

方法一:

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
int flag=1;
const int N=1e4+10;
int son[N][2],cnt[N],idx;
vector<string>vec;
void insert(string s)
{
	int p=0,u;
	for(int i=0;i<s.length();i++)
	{
		u=s[i]-'0';
		if(!son[p][u]) son[p][u]=++idx;
		p=son[p][u];
		cnt[p]++;
	}
}
void init()
{
	idx=0,flag=1; vec.clear();
	for(int i=0;i<N;i++) son[i][0]=son[i][1]=cnt[i]=0;
}
bool que(string s)
{
	int p=0,u;
	for(int i=0;i<s.length();i++)
	{
		u=s[i]-'0';
		if(!son[p][u]) son[p][u]=++idx;
		p=son[p][u];
	}
	if(cnt[p]>=2) return 0;
	return 1;
}
int main()
{
	string s;
	int cas=1;
	init();
	while(cin>>s)
	{
		if(s=="9")
		{
			for(auto i:vec) flag*=que(i);
			if(flag) cout<<"Set "<<cas<<" is immediately decodable\n";
			else cout<<"Set "<<cas<<" is not immediately decodable\n";
			cas++;
			init();
			continue;
		}
		insert(s); vec.push_back(s);
	}
	return 0;
}

方法二:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
int flag=1;
const int N=1e4+10;
int son[N][2],cnt[N],idx;
int insert(string s)
{
	int p=0,u;
	for(int i=0;i<s.length();i++)
	{
		u=s[i]-'0';
		if(!son[p][u]) son[p][u]=++idx;
		p=son[p][u];
		if(cnt[p]) return 0;
	}
	cnt[p]++;
	if(son[p][0] || son[p][1]) return 0;
	return 1;
}
void init()
{
	idx=0,flag=1;
	for(int i=0;i<N;i++) son[i][0]=son[i][1]=cnt[i]=0;
}
int main()
{
	string s;
	int cas=1;
	init();
	while(cin>>s)
	{
		if(s=="9")
		{
			if(flag) cout<<"Set "<<cas<<" is immediately decodable\n";
			else cout<<"Set "<<cas<<" is not immediately decodable\n";
			cas++;
			init();
			continue;
		}
		if(flag) flag*=insert(s);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值