题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1003&cid=778
The Dominator of Strings
Time Limit: 3000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 0 Accepted Submission(s): 0
Problem Description
Here you have a set of strings. A dominator is a string of the set dominating all strings else. The string
S
is dominated by
T
if
S
is a substring of
T
.
Input
The input contains several test cases and the first line provides the total number of cases.
For each test case, the first line contains an integer N indicating the size of the set.
Each of the following N lines describes a string of the set in lowercase.
The total length of strings in each case has the limit of 100000 .
The limit is 30MB for the input file.
For each test case, the first line contains an integer N indicating the size of the set.
Each of the following N lines describes a string of the set in lowercase.
The total length of strings in each case has the limit of 100000 .
The limit is 30MB for the input file.
Output
For each test case, output a dominator if exist, or No if not.
Sample Input
3 10 you better worse richer poorer sickness health death faithfulness youbemyweddedwifebetterworsericherpoorersicknesshealthtilldeathdouspartandpledgeyoumyfaithfulness 5 abc cde abcde abcde bcde 3 aaaaa aaaab aaaac
Sample Output
youbemyweddedwifebetterworsericherpoorersicknesshealthtilldeathdouspartandpledgeyoumyfaithfulness abcde No
Source
输入输出测试
后来又参考一篇博客(自己AC自动机学得太差了……),修改一下过了。主要参考这篇博客(http://blog.sina.com.cn/s/blog_69c3f0410100tztt.html),打算有时间好好拜读一下。
#include<stdio.h>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define M 10010
struct trie{
int sign;//是否为该单词的最后一个结点
int fail;//失配指针
int next[26];//26个字母方向的子结点
}t[100005];
int q[100005],head,tail,L;
char str[100005],s[100005];
void Insert(char *a)//将单词插入字典树
{
int i=0,p=0,j,x;
while(a[i]){
x=t[p].next[a[i]-'a'];
if(x<0){//前面字符串未访问过此处,则申请新结点
t[p].next[a[i]-'a']=x=++L;//数组模拟链表申请新结点(即++L操作)
for(j=0;j<26;j++)t[x].next[j]=-1;
t[x].fail=-1;t[x].sign=0;//初始化新结点信息
}
p=x;
i++;
}
t[p].sign++;
}
void build_ACauto()//更新失配指针
{
int i,x,y,p;
t[0].fail=-1;
q[tail++]=0;//将根放入队列
while(head<tail){
x=q[head++];//取队首元素
for(i=0;i<26;i++){
y=t[x].next[i];
if(y>=0){
if(!x)t[y].fail=0;//如果x为根结点,那么他的子结点的失配指针为头结点
else{
p=t[x].fail;//取父结点的失配指针
while(p>=0){//如果失配指针不为空,继续找
if(t[p].next[i]>=0){//如果找到结点与相配
t[y].fail=t[p].next[i];//将失配指针指向它后退出循环
break;
}
p=t[p].fail;//否则继续往上找
}
if(p<0)t[y].fail=0;//如果最终还是没有找到,则失配指针指向根结点
}
q[tail++]=y;//将子结点存入队尾
}
}
}
}
int ACauto()//在字典树中查找s的子串在树中出现的次数
{
int i=0,j,p=0,x,num=0;
while(s[i]){
j=s[i]-'a';
while(t[p].next[j]<0&&p)p=t[p].fail;//从字典树中找到相配结点或到达根时退出
p=t[p].next[j];//指向找到的结点所对应字母
if(p<0)p=0;//如果没有找到,指针指向根结点
x=p;
while(x&&t[x].sign!=-1){//如果不是根结点且未访问过,则继续查找
num+=t[x].sign;
t[x].sign=-1;
x=t[x].fail;//由失配指针向上查找
}
i++;
}
return num;
}
int main()
{
int T,n,i;
scanf("%d",&T);
while(T--)
{
head=tail=L=0;
t[0].fail=-1;//初始化头结点信息
t[0].sign=0;
for(i=0;i<26;i++)t[0].next[i]=-1;
scanf("%d",&n);
int len=0,tem;
for(i=0;i<n;i++)
{
scanf("%s",str);
tem=strlen(str);
if(tem>len)
{
len=tem;
strcpy(s,str);
}
Insert(str);//将读入的字符串插入字典树
}
build_ACauto();//更新字典树中的失配符
// printf("%d\n",ACauto());//在字典树查找子串出现在字典树中的次数
if(n==ACauto())
printf("%s\n",s);
else
printf("No\n");
}
return 0;
}