题意:n个字符串(n<=10)求最长公共子串的长度

前置技能点:https://www.cnblogs.com/wenci/p/10432932.html (两个字符串求最长公共子串的长度)

既然知道了两个串的最长公共子串怎么求

那我们延伸一下,考虑两个变量,maxx表示在当前拿上来匹配得这个串在每个节点为终点时最长匹配的长度

minn表示在之前所有串上匹配完,到当前节点最长匹配的长度

先解释一下拓扑序的基数排序

inline void radix_sort(){
int i,j,k;
for(i=;i<=tot;i++){
tong[node[i].len]++;
}//开桶记录长度
for(i=;i<=tot;i++){
tong[i]+=tong[i-];
}//表示当前长度能排到多少名
for(i=;i<=tot;i++){
id[tong[node[i].len]--]=i;//重新排序后的数值
}
}

每一个串重新匹配的操作

inline bool work(){
if(scanf("%s",s)==EOF) return false;
int p=,len=;int i,j,k;
for(i=;i<=tot;i++){
node[i].maxx=;
}//把当前串的最大匹配清零
int l1=strlen(s);
for(i=;i<l1;i++){
int now=s[i]-'a'+;
if(node[p].ch[now]){
p=node[p].ch[now];len++;
}
else{
while(p&&!node[p].ch[now]){
p=node[p].fa;
}
if(!p){
p=;len=;
}
else{
len=node[p].len+;p=node[p].ch[now];
}
}//以上都和两个串匹配操作一样
node[p].maxx=max(node[p].maxx,len);//这里更新一下当前串的最大匹配
}
for(i=tot;i;i--){//按照倒拓扑序,要优先修改儿子节点更新父亲节点
int t=id[i];//基数排序后的序号
node[t].minn=min(node[t].minn,node[t].maxx);//更新当前节点的最大匹配
if(node[t].maxx>=node[t].len&&node[t].fa){//如果当前节点是满匹配的,那么删去结尾最后一个,也是满匹配的
node[node[t].fa].maxx=node[node[t].fa].len;//把父亲节点的匹配也更新了
}
}
return true;
}

最后贴整篇代码

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
inline int read(){
int w=,f=;
char ch=getchar();
while(ch<''||ch>''){
if(ch=='-') f=-;
ch=getchar();
}
while(ch>=''&&ch<=''){
w=(w<<)+(w<<)+ch-;
ch=getchar();
}
return w*f;
}
int n,m,lst=,tot=;
long long size[],sum[];
struct Node{
int ch[],len,fa,maxx,minn;
}node[];
bool flag;
inline void extend(int now){
int p=lst;tot++;lst=tot;int np=tot;
node[np].len=node[p].len+;
while(p&&!node[p].ch[now]){
node[p].ch[now]=np;
p=node[p].fa;
}
if(!p) node[np].fa = ;
else{
int q = node[p].ch[now];
if(node[q].len == node[p].len + ){
node[np].fa = q;
}
else{
int nq=++tot;node[nq]=node[q];
node[nq].len=node[p].len+;
node[np].fa=node[q].fa=nq;
while(p&&node[p].ch[now] == q){
node[p].ch[now]=nq;
p=node[p].fa;
}
}
}
}
int tong[],id[],ans;
char s[];
inline void radix_sort(){
int i,j,k;
for(i=;i<=tot;i++){
tong[node[i].len]++;
}
for(i=;i<=tot;i++){
tong[i]+=tong[i-];
}
for(i=;i<=tot;i++){
id[tong[node[i].len]--]=i;
}
}
inline bool work(){
if(scanf("%s",s)==EOF) return false;
int p=,len=;int i,j,k;
for(i=;i<=tot;i++){
node[i].maxx=;
}
int l1=strlen(s);
for(i=;i<l1;i++){
int now=s[i]-'a'+;
if(node[p].ch[now]){
p=node[p].ch[now];len++;
}
else{
while(p&&!node[p].ch[now]){
p=node[p].fa;
}
if(!p){
p=;len=;
}
else{
len=node[p].len+;p=node[p].ch[now];
}
}
node[p].maxx=max(node[p].maxx,len);
}
for(i=tot;i;i--){
int t=id[i];
node[t].minn=min(node[t].minn,node[t].maxx);
if(node[t].maxx>=node[t].len&&node[t].fa){
node[node[t].fa].maxx=node[node[t].fa].len;
}
}
return true;
}
int main(){
scanf("%s",s);int i,j,k;
int l=strlen(s);
for(i=;i<=l;i++){
extend(s[i]-'a'+);
}
radix_sort();
for(i=;i<=tot;i++){
node[i].minn=node[i].len;
}
while(work());
for(i=;i<=tot;i++){
ans=max(ans,node[i].minn);
}
cout<<ans<<endl;
return ;
}

最长公共子串2(LCS2) lg SP1812的更多相关文章

  1. 多个串的最长公共子串 SPOJ - LCS2 后缀自动机

    题意: 求多个串的最长公共子串 这里用的是O(n)的后缀自动机写法 我后缀数组的专题有nlog(n)写法的 题解: 对于其中的一个串建立后缀自动机 然后对于后缀自动机上面的每一个节点求出每一个节点最长 ...

  2. SPOJ LCS2 多个串的最长公共子串

    这里串最多有10个,找所有串的最长公共子串 这里后缀自动机做,以第一个串建立后缀自动机,后面的串一个个去匹配,每次得到当前串在可到达状态上所能得到的最长后缀长度 拿所有串匹配后得到的结果进行计算 #i ...

  3. 最长公共子串(LCS) lg SP1811

    后缀自动机的一大用处就是求最长公共子串了 这道题的话题意就是给你两个字符串,求最长公共子串 做法的话是先使用一个字符串建立SAM,然后让另一个串在上面进行匹配 匹配的策略是优先匹配当前节点的下一个字符 ...

  4. 算法设计 - LCS 最长公共子序列&&最长公共子串 &&LIS 最长递增子序列

    出处 http://segmentfault.com/blog/exploring/ 本章讲解:1. LCS(最长公共子序列)O(n^2)的时间复杂度,O(n^2)的空间复杂度:2. 与之类似但不同的 ...

  5. [Data Structure] LCSs——最长公共子序列和最长公共子串

    1. 什么是 LCSs? 什么是 LCSs? 好多博友看到这几个字母可能比较困惑,因为这是我自己对两个常见问题的统称,它们分别为最长公共子序列问题(Longest-Common-Subsequence ...

  6. HDU 1503 带回朔路径的最长公共子串

    http://acm.hdu.edu.cn/showproblem.php?pid=1503 这道题又WA了好几次 在裸最长公共子串基础上加了回溯功能,就是给三种状态各做一个 不同的标记.dp[n][ ...

  7. 最长公共子序列PK最长公共子串

    1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. (1)递归方法求最长公共子序列的长度 1) ...

  8. 动态规划(一)——最长公共子序列和最长公共子串

    注: 最长公共子序列采用动态规划解决,由于子问题重叠,故采用数组缓存结果,保存最佳取值方向.输出结果时,则自顶向下建立二叉树,自底向上输出,则这过程中没有分叉路,结果唯一. 最长公共子串采用参考串方式 ...

  9. 字符串hash + 二分答案 - 求最长公共子串 --- poj 2774

    Long Long Message Problem's Link:http://poj.org/problem?id=2774 Mean: 求两个字符串的最长公共子串的长度. analyse: 前面在 ...

随机推荐

  1. RT-Thread can - STM32F103ZET6

    SDK版本v4.0.2 目前,RT-Thread Studio还不能够自定义添加can设备.下面介绍手动添加过程: 使用RT-Thread Studio创建一个简单工程 使用RT-Thread env ...

  2. VMware使用与安装

    VMware安装 下载完Vmware -> 双击打开安装包 -> 选择下一步(如下图界面) 选择接受协议,点击下一步 选择经典进行安装.这个是默认安装,会把默认插件安装到相对应的路径 选择 ...

  3. go 序列化

    序列化 package main import ( "encoding/json" "fmt" ) //结构体 type Monster struct { Na ...

  4. vim编辑超大文件

    进入大文件(12g,250w+ lines),vim,耐心等待 有两种方法编辑删除冗余字段 1.set number ,可以通过:+数字组合跳到指定行,输入命令   ":100,200d&q ...

  5. [转载]花了半个月,终于把Python库全部整理出来了,非常全面

    库名称简介 Chardet 字符编码探测器,可以自动检测文本.网页.xml的编码. colorama 主要用来给文本添加各种颜色,并且非常简单易用. Prettytable 主要用于在终端或浏览器端构 ...

  6. XSS跨站测试代码

    '><script>alert(document.cookie)</script>='><script>alert(document.cookie)&l ...

  7. es5和es6创建新数组的方法

    //es5 let array = Array(5) let array = [] //es6 1.let array = Array.of(1,2,3,4,5) 2.let array = Arra ...

  8. 纪中21日c组模拟赛

    AWSL  AWSL  AWSL  AWSL AWSL  AWSL  AWSL  AWSL AWSL  AWSL  AWSL  AWSL AWSL  AWSL  AWSL  AWSL 题解传送 T1  ...

  9. windows下安装openjdk

    redhat版openjdk,解压后就能用,下载地址https://developers.redhat.com/products/openjdk/download. Azul Zulu版openjdk ...

  10. CentOS7防火墙设置常用命令

    目录 开/关/重启防火墙 查看所有开启的端口号 CentOS7环境下防火墙常用命令 开/关/重启防火墙 查看防火墙状态 firewall-cmd --state 启动防火墙 systemctl sta ...