您的位置:首页 > 其它

poj2774Long Long Message【后缀数组求最长公共字串】

2016-02-20 16:27 435 查看
Description
The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days: his mother is getting ill. Being worried about spending so much on railway tickets (Byterland is such a big country,
and he has to spend 16 shours on train to his hometown), he decided only to send SMS with his mother.

The little cat lives in an unrich family, so he frequently comes to the mobile service center, to check how much money he has spent on SMS. Yesterday, the computer of service center was broken, and printed two very long messages. The brilliant little cat soon
found out:

1. All characters in messages are lowercase Latin letters, without punctuations and spaces.

2. All SMS has been appended to each other – (i+1)-th SMS comes directly after the i-th one – that is why those two messages are quite long.

3. His own SMS has been appended together, but possibly a great many redundancy characters appear leftwards and rightwards due to the broken computer.

E.g: if his SMS is “motheriloveyou”, either long message printed by that machine, would possibly be one of “hahamotheriloveyou”, “motheriloveyoureally”, “motheriloveyouornot”, “bbbmotheriloveyouaaa”, etc.

4. For these broken issues, the little cat has printed his original text twice (so there appears two very long messages). Even though the original text remains the same in two printed messages, the redundancy characters on both sides would be possibly different.

You are given those two very long messages, and you have to output the length of the longest possible original text written by the little cat.

Background:

The SMS in Byterland mobile service are charging in dollars-per-byte. That is why the little cat is worrying about how long could the longest original text be.

Why ask you to write a program? There are four resions:

1. The little cat is so busy these days with physics lessons;

2. The little cat wants to keep what he said to his mother seceret;

3. POJ is such a great Online Judge;

4. The little cat wants to earn some money from POJ, and try to persuade his mother to see the doctor :(

Input
Two strings with lowercase letters on two of the input lines individually. Number of characters in each one will never exceed 100000.
Output
A single line with a single integer number – what is the maximum length of the original text written by the little cat.
Sample Input
yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother

Sample Output
27

Source
POJ Monthly--2006.03.26,Zeyuan Zhu,"Dedicate to my great beloved mother."

后缀数组好难QAQ一上午都没看懂模板,一下午才套模板写出来一道题,还是借鉴网上写的==等明天做明白再写分析

本题题解:后缀数组原本只是求是后缀数组及其相关数量关系的,要是求两个串的最长公共子串就把第二个接到第一个后面,中间用一个没出现过的字符连接,下标顺延(这里出了一个傻逼错误是下标忘记++了),最后还得加一个0.最后寻找height[]的最大值,而且必须是来自两个子串的

/******************
poj2774
2016.2.20
5400K 563MS G++ 2375B
******************/
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int MAXN=200007;
int sa[MAXN];//SA数组,表示将S的n个后缀从小到大排序后把排好序的
//的后缀的开头位置顺次放入SA中
int t1[MAXN],t2[MAXN],c[MAXN];//求SA数组需要的中间变量,不需要赋值
int rank[MAXN],height[MAXN];
//待排序的字符串放在s数组中,从s[0]到s[n-1],长度为n,且最大值小于m,
//除s[n-1]外的所有s[i]都大于0,r[n-1]=0
//函数结束以后结果放在sa数组中
void build_sa(int s[],int n,int m)
{
int i,j,p,*x=t1,*y=t2;
//第一轮基数排序,如果s的最大值很大,可改为快速排序
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[i]=s[i]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];
for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
// for(int i=0;i<n;i++) printf("i=%d sa=%d x=%d\n",i,sa[i],x[i]);
for(j=1;j<=n;j<<=1)
{
p=0;
//直接利用sa数组排序第二关键字
for(i=n-j;i<n;i++)y[p++]=i;//后面的j个数第二关键字为空的最小
for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
//这样数组y保存的就是按照第二关键字排序的结果
//基数排序第一关键字
for(i=0;i<m;i++)c[i]=0;
for(i=0;i<n;i++)c[x[y[i]]]++;
for(i=1;i<m;i++)c[i]+=c[i-1];

for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
// for(int i=0;i<p;i++) printf("j=%d i=%d x=%d y=%d sa=%d\n",j,i,x[i],y[i],sa[i]);
//根据sa和x数组计算新的x数组
swap(x,y);
p=1;x[sa[0]]=0;
for(i=1;i<n;i++)
x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
if(p>=n)break;
m=p;//下次基数排序的最大值
}
}
void getHeight(int s[],int n)
{
int i,j,k=0;
for(i=0;i<=n;i++)rank[sa[i]]=i;
for(i=0;i<n;i++)
{
if(k)k--;
j=sa[rank[i]-1];
while(s[i+k]==s[j+k])k++;
height[rank[i]]=k;
}
}

int r[MAXN];
char str1[MAXN],str2[MAXN];
int main()
{
//freopen("cin.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%s%s",str1,str2);
int n=0;
int len=strlen(str1);
for(int i=0;i<len;i++) r[n++]=str1[i]-'a'+1;
r[n++]=30;
len=strlen(str2);
for(int i=0;i<len;i++) r[n++]=str2[i]-'a'+1;
r
=0;
build_sa(r,n+1,31);
getHeight(r,n);
len=strlen(str1);
int maxx=0;
for(int i=2;i<=n;i++)
{
if(height[i]>maxx)
{
if(0<=sa[i-1]&&sa[i-1]<len&&len<sa[i])
maxx=height[i];
if(0<=sa[i]&&sa[i]<len&&len<sa[i-1])
maxx=height[i];
}
}
printf("%d\n",maxx);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: