poj 3080 后缀自动机

   这道题大家都暴力过了,因为题目数据小 ,但如果数据大了肿么办~~,这道题还可以 用后缀数组+栈扫描 (或二分)解. 不过效率很都不如后缀自动机。

   姑且用它来练练后缀自动机吧

#include<stdio.h>   
#include<string.h>   
#include <cmath>
#include<algorithm>   
#define fr(i,s,n) for(int i=s;i<n;i++)
#define fi freopen("in.txt","r",stdin)
#define fo freopen("output.txt","w",stdout)
#define cl(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int  maxn=130;
const int kinds=26;

char ch[maxn];

struct Sam{
	Sam *son[kinds],*fa;
	int l ,mlcs,nowlcs;
	int fach,pos;
}a[maxn],*head,*last;

int top=-1;
Sam *b[maxn];
int dws[maxn],len;

void init(){
	top = -1;
	a[0].l = 0;
	fr(i , 0 ,maxn) {
		a[i].fa = NULL;
		a[i].nowlcs = 0;
		fr(k,0,kinds) a[i].son[k] = NULL;
		cl(dws);
	}
}
void add(int x,int pos){
	Sam *p=&a[++top],*bj=last;
	p->pos = pos,p->l= p->mlcs =last->l+1;last=p; 
	for(; bj && !bj->son[x] ; bj = bj->fa) bj->son[x] = p;
	if (!bj) {p->fa = head;}
	else if (bj->l+1 == bj->son[x]->l)  p->fa = bj->son[x];
	else{
		Sam *r = &a[ ++ top],*q = bj->son[x]; r->pos = pos;
		*r = *q ,r->l= r->mlcs = bj->l+1, p->fa = q->fa = r; 
		for( ; bj && bj->son[x] == q; bj = bj->fa) bj->son[x] = r;
	}
}

char str[100];

struct Anscer{
	char A[61];
}Ans[61];

bool cmp(Anscer x,Anscer y){
	return strcmp(x.A,y.A)<= 0;
}
int main(){

	int t,tot;
	scanf("%d",&t);
	while(t--){
		init();
		scanf("%d",&tot); --tot;
		scanf("%s",ch);strcpy(str,ch);
		head = last = &a[++top];
		int n=strlen(ch);
		fr(i,0,n) add( ch[i] - 'A',i);
		int i;
		for (i = 0; i <= top; ++i) ++dws[a[i].l]; 
		for (i = 1; i <= n; ++i)	dws[i] += dws[i - 1];   
		for (i = 0; i <= top; ++i)   b[--dws[a[i].l]] = &a[i];

		while(tot--){
			scanf("%s",ch);
			
			len = strlen(ch);
			int mid = 0, y;
			last = head;
			for(int i=0;i<len;++i){
				if (last ->son[y = ch[i] - 'A' ]){
					++ mid;
					last = last->son[y];
					if (mid >last->nowlcs) last->nowlcs = mid;
				}
				else{
					for (; last && !last->son[y]; last = last->fa);
					if (!last) mid = 0,last = head;
					else{
						mid = last->l + 1;
						last = last->son[y];
						if (mid > last->nowlcs) last->nowlcs = mid;
					}
				}
			}
			for (int i=top ; i>0;--i){
				if ( b[i]->nowlcs <b[i]->mlcs) b[i]->mlcs = b[i]->nowlcs;
				if (b[i]->fa->nowlcs < b[i]->nowlcs) b[i]->fa->nowlcs = b[i]->nowlcs;
				b[i]->nowlcs = 0;
			}
		}
		int ans=0,anspos[61],totans=0;

		fr(i , 0 ,top+1){
			if (a[i].mlcs > ans) {
				ans = a[i].mlcs;			
				totans =0;
				anspos[totans++] = i;
			}
			else if (a[i].mlcs == ans){
				anspos[totans++] = i;
			}
		}
		if (ans<3){
			printf("no significant commonalities\n");
		}
		else{
			fr(i,0,totans){
				int tmp = a[ anspos[i] ].pos;
				int id=0;
				for(int k = tmp - ans+1; k<=tmp ;k++){
					Ans[i].A[id++] = str[k];
				}
				Ans[i].A[id] = '\0';
			}
			sort(Ans,Ans+totans,cmp);
			printf("%s\n",Ans[0].A);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值