bzoj1195 [HNOI2006]最短母串

http://www.elijahqi.win/archives/3512
Description
给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。

Input
第一行是一个正整数n(n<=12),表示给定的字符串的个数。
以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.
Output
只有一行,为找到的最短的字符串T。在保证最短的前提下,
如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。
Sample Input
2
ABCD
BCDABC
Sample Output
ABCDABC
HINT

Source
AC自动机忘了调试很久 卡内存 调试很久?

设dp[i][s]表示现在在AC自动机上的第i个节点我现在匹配了s状态的串最短需要几个字母完全匹配 因为要求字典序最小 所以我直接贪心的从0~25转移并且 采用bfs的方法 即使得最后匹配出来的是最短的 往子树走 因为子树可能包含更多的串

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fi first
#define se second
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
#define Pa pair<int,pair<int,int> >
using namespace std;
const int N=602;
char s[66];int trans[N][26],q1[N],top,n,end[N],fail[N],cnt=1;
inline void insert1(int id){
    scanf("%s",s+1);int p=1;
    for (int i=1,nxt;s[i];++i){
        if (!trans[p][s[i]-'A']) trans[p][s[i]-'A']=nxt=++cnt;
        else nxt=trans[p][s[i]-'A'];p=nxt;
    }end[p]|=1<<id;
}
inline void build(){
    queue<int>q;q.push(1);for (int i=0;i<26;++i) trans[0][i]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        for (int i=0;i<26;++i){
            int &y=trans[x][i];
            if (!y) {y=trans[fail[x]][i];continue;}
            fail[y]=trans[fail[x]][i];q.push(y);end[y]|=end[fail[y]];
        }
    }
}
pa pre[N][4100];bool visit[N][4100];int pre1[N][4100];
int main(){
    freopen("bzoj1195.in","r",stdin);
    scanf("%d",&n);int S=(1<<n)-1;
    for (int i=0;i<n;++i) insert1(i);build();
    queue<pa> q;q.push(mp(1,0));int h=1,t=1;
    while(!q.empty()){
        pa t=q.front();q.pop();
        int x=t.fi,s=t.se;
        if (s==S){
            pa tmp=mp(x,s);
            while(1){
                q1[++top]=pre1[tmp.fi][tmp.se];
                int x=tmp.fi,s=tmp.se;
                tmp=pre[x][s];
                if (tmp.fi==1&&tmp.se==0) break;
            }
            for (int i=top;i;--i)putchar(q1[i]+'A');
            return 0;
        }
        for (int i=0;i<26;++i){
            int y=trans[x][i];
            if (visit[y][s|end[y]]) continue;
            q.push(mp(y,s|end[y]));
            pre[y][s|end[y]]=mp(x,s);
            pre1[y][s|end[y]]=i;
            visit[y][s|end[y]]=1;
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值