[HNOI2006]最短母串问题

题目大意:给定一个字符串集,求一个最短字串,使得该集合内的串都是该串的一个子串

算法:AC自动机+最短路+状压DP

注意空间限制

#include"cstdio"
#include"cstring"
#include"iostream"
#include"algorithm"
#include"bitset"
#include"string"
using namespace std;

const int MAXN=13;
const int MAXM=55;
const int siz=26;

int n,cnt,minn;
string ans;
short q[MAXN*MAXM*siz];
int ln[MAXN*MAXM],f[MAXN][MAXN],I[MAXN][1<<12];
string G[MAXN*MAXM],g[MAXN][MAXN],H[MAXN][1<<12];
int rid[MAXN];
char ch[MAXM*MAXN];
bitset<MAXN*MAXM> vis;
struct rpg{
    int fail;
    int sn[siz];
}T[MAXN*MAXM];

void ins(char *ch,int id)
{
    int ln=strlen(ch+1),nw=0;
    for(int i=1;i<=ln;++i){
        if(!T[nw].sn[ch[i]-'A']) T[nw].sn[ch[i]-'A']=++cnt;
        nw=T[nw].sn[ch[i]-'A'];
    }rid[id]=nw;
    return;
}

void Getfail()
{
    int hd=1,tl=0;
    for(int i=0;i<siz;++i) if(T[0].sn[i]) q[++tl]=T[0].sn[i];
    while(hd<=tl){
        int nw=q[hd++];
        for(int i=0;i<siz;++i){
            if(T[nw].sn[i]){
                T[T[nw].sn[i]].fail=T[T[nw].fail].sn[i];
                q[++tl]=T[nw].sn[i];
            }else T[nw].sn[i]=T[T[nw].fail].sn[i];
        }
    }return;
}

void SPFA(int s)
{
    int hd=1,tl=1;
    memset(ln,0x7f,sizeof(ln));
    for(int i=1;i<=cnt;++i) G[i].clear();
    q[hd]=s;ln[s]=0;vis[s]=1;
    while(hd<=tl){
        int nw=q[hd++];vis[nw]=0;
        if(ln[T[nw].fail]>ln[nw]){
            ln[T[nw].fail]=ln[nw];
            G[T[nw].fail]=G[nw];
            if(!vis[T[nw].fail]){
                vis[T[nw].fail]=1;
                q[++tl]=T[nw].fail;
            }
        }for(int i=0;i<siz;++i){
            string str=G[nw]+(char)(i+'A');
            if(ln[T[nw].sn[i]]<ln[nw]+1) continue;
            if(ln[T[nw].sn[i]]>ln[nw]+1){
                ln[T[nw].sn[i]]=ln[nw]+1;
                G[T[nw].sn[i]]=str;
                if(!vis[T[nw].sn[i]]){
                    vis[T[nw].sn[i]]=1;
                    q[++tl]=T[nw].sn[i];
                }
            }if(G[T[nw].sn[i]]<=str) continue;
            G[T[nw].sn[i]]=str;
            if(!vis[T[nw].sn[i]]){
                vis[T[nw].sn[i]]=1;
                q[++tl]=T[nw].sn[i];
            }
        }
    }return;
}

void res()
{
    SPFA(0);
    for(int i=1;i<=n;++i){
        f[0][i]=ln[rid[i]];
        g[0][i]=G[rid[i]];
    }for(int i=1;i<=n;++i){
        SPFA(rid[i]);
        for(int j=1;j<=n;++j){
            f[i][j]=ln[rid[j]];
            g[i][j]=G[rid[j]];
        }
    }return;
}

void slv()
{
    memset(I,0x7f,sizeof(I));
    for(int i=1;i<=n;++i) I[i][1<<i-1]=f[0][i],H[i][1<<i-1]=g[0][i];
    for(int i=1;i<1<<n;++i){
        for(int j=1;j<=n;++j){
            if((i>>j-1)&1==0) continue;
            for(int k=1;k<=n;++k){
                if((i>>k-1)&1) continue;
                if(I[k][i|(1<<k-1)]<I[j][i]+f[j][k]) continue;
                if(I[k][i|(1<<k-1)]>I[j][i]+f[j][k]){
                    I[k][i|(1<<k-1)]=I[j][i]+f[j][k];
                    H[k][i|(1<<k-1)]=H[j][i]+g[j][k];
                }else if(H[k][i|(1<<k-1)]>H[j][i]+g[j][k]){
                    H[k][i|(1<<k-1)]=H[j][i]+g[j][k];
                }
            }
        }
    }ans=H[1][(1<<n)-1],minn=I[1][(1<<n)-1];
    for(int i=2;i<=n;++i){
        if(minn>I[i][(1<<n)-1]){
            minn=I[i][(1<<n)-1];
            ans=H[i][(1<<n)-1];
        }else if(minn==I[i][(1<<n)-1]&&ans>H[i][(1<<n)-1]){
            ans=H[i][(1<<n)-1];
        }
    }return;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%s",ch+1),ins(ch,i);
    Getfail();res();slv();
    cout<<ans<<endl;
    return 0;
}

转载于:https://www.cnblogs.com/AH2002/p/10019683.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值