传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1671
【分析】这个题目意识是在这一组数据中不出现某个数据作为某个数据的前缀。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Tire //建立一个结点的结构体
{
int end; //判断是否是一个单词的终点
struct Tire *child[11]; //10个分支结点
}tree;
tree *root; //定义一个Tire的指针
int flag; //判断这组数据是否出现某个电话是另一个电话的前缀
void insert(char *s) //插入这个单词并判断①这个单词是否会成为别的单词的前缀
//判断②是否有别的单词成为这个单词的前缀
{
int i, j;
int len = strlen(s);
tree *a = root;
for (i = 0; i<len; i++)
{
int k = s[i] - '0';
if (a->child[k] != NULL) //一个数字一个数字查找,如果发现该数字后面的节点不为空,证明他后面的这个孩子分支存在。
{
a = a->child[k]; //将a的指针指向这个孩子分支
if (a->end == 1) //判断②如果这个节点的end标记为1,代表有某个号码成为这个号码的前缀。
{
flag = 1; //flag==1,代表要输出NO,直接退出循环
return;
}
}
else
{
tree *temp = (tree*)malloc(sizeof(tree));// 为temp申请动态内存
a->child[k] = temp; //将a的下一层节点k位置 指向temp,a的temp孩子不是空的,但是temp的孩子分支都是空的;
for (j = 0; j<10; j++)
temp->child[j] = NULL;
a = temp;
}
}
a->end = true; // 将该数串最后一个节点的 标记变量置为true;
for (int i = 0; i<10; i++)
{
if (a->child[i] != NULL) //判断①,证明这个号码成为了别的号码的前缀,
{
flag = 1;
return;
}
}
}
void end(struct Tire *p) //释放内存
{
int i;
for (i = 0; i<10; i++)
if (p->child[i] != NULL) end(p->child[i]);
delete(p);
}
int main()
{
int t;
scanf("%d", &t);
char s[10005];
while (t--)
{
root = (tree*)malloc(sizeof(tree));//申请内存
for (int i = 0; i<10; i++)
root->child[i] = NULL;
flag = 0; //初始化这组数据未发现问题
int n;
scanf("%d", &n);
for (int i = 0; i<n; i++)
{
scanf("%s", s);
insert(s);
}
if (flag)
printf("NO\n");
else
printf("YES\n");
end(root); //每一次都必须要释放内存,否则会MTL
}
}