poj_3630 trie树

题目大意

    给定一系列电话号码,查看他们之间是否有i,j满足,号码i是号码j的前缀子串。

题目分析

    典型的trie树结构。直接使用trie树即可。但是需要注意,若使用指针形式的trie树,则在大数据量下new/delete会很耗时,因此使用静态数组来存储trie树结构。使用静态数组代替指针在oj中常用于节省时间!

实现(c++)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#define MAX_CHILD_NUM 10
#define MAX_NODE_NUM 1 << 16
struct TrieNode{
	int count;
	int childs[MAX_CHILD_NUM];
	TrieNode(){
		count = 0;
		memset(childs, 0, sizeof(childs));
	}
};

TrieNode gNodes[MAX_NODE_NUM];	//静态数组方式存储
int gCount;
bool Insert(int root, char* str){
	int node = root;
	char* p = str;
	while (*p != '\0'){
		int index = *p - '0';
		if (gNodes[node].childs[index] == 0){
			gNodes[node].childs[index] = gCount++;
		}
		node = gNodes[node].childs[index];
		if (gNodes[node].count == 2){		//若为某个号码的结尾,则说明出现了前缀子串。
			return false;
		}
		if (*(p + 1) == '\0'&&gNodes[node].count == 1){		//特殊情况,画图分析很容易看出
			return false;
		}
		gNodes[node].count = 1;		//为1 表示该节点是某个号码内部的点
		p++;
	}
	if (gNodes[node].count == 2){		//为2说明该点是某个号码结尾的点
		return false;
	}
	gNodes[node].count = 2;
	return true;
}


int main(){
	int cas;
	char number[20];
	scanf("%d", &cas);
	for (int i = 0; i < cas; i++){
		memset(gNodes, 0, sizeof(gNodes));
		gCount = 2;

		int n;
		scanf("%d", &n);
		getchar();
		bool flag = true;
		for (int k = 0; k < n; k++){
			scanf("%s", number);
			if (flag)
				flag = Insert(1, number);
		}
		if (!flag)
			printf("NO\n");
		else
			printf("YES\n");
	}
	return 0;
}

 

posted @ 2015-09-16 23:47  农民伯伯-Coding  阅读(291)  评论(0编辑  收藏  举报