BZOJ1195 HNOI2006最短母串(状压dp)

  按照子串出现的先后考虑。令f[i][j]为已经出现的字符串集合为i,最后一个出现的字符串为j时的最短串长,预处理一下任意两个串的最长重叠长度,转移显然。有点麻烦的是字典序,强行增加代码难度。

  另一个比较简单的做法是上AC自动机,建出来后类似地令f[i][j]为已经出现的字符串集合为i,在自动机上点j时的最短串长,相当于跑一个最短路,bfs时每次优先选字典序最小的边即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 12
#define M 52
int n,len[N],d[N][N];
char s[N][M];
struct str
{
    int n;char s[N*M];
    bool operator <(const str&a) const
    {
        for (int i=1;i<=n;i++)
        if (s[i]!=a.s[i]) return s[i]<a.s[i];
        return 1;
    }
};
str get(int p,int q);
struct data
{
    int i,j,x,n,s[N+1];
    bool operator <(const data&a) const
    {
        if (x!=a.x) return x<a.x;
        return get(i,j)<get(a.i,a.j);
    }
}f[1<<N][N];
str get(int p,int q)
{
    int n=f[p][q].n;
    str v;memset(v.s,0,sizeof(v.s));
    int x=len[f[p][q].s[1]];
    for (int i=1;i<=len[f[p][q].s[1]];i++) v.s[i]=s[f[p][q].s[1]][i];
    for (int i=2;i<=n;i++)
        for (int j=d[f[p][q].s[i-1]][f[p][q].s[i]]+1;j<=len[f[p][q].s[i]];j++)
        v.s[++x]=s[f[p][q].s[i]][j];
    v.n=x;
    return v;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj1195.in","r",stdin);
    freopen("bzoj1195.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read();
    for (int i=0;i<n;i++) scanf("%s",s[i]+1),len[i]=strlen(s[i]+1);
    for (int i=0;i<n;i++)
        for (int j=0;j<n;j++)
        if (i!=j)
            for (int k=1;k<=len[i];k++)
            {
                bool flag=1;
                for (int x=1;x<=len[j]&&k+x-1<=len[i];x++)
                if (s[i][k+x-1]!=s[j][x]) {flag=0;break;}
                if (flag) {d[i][j]=min(len[i]-k+1,len[j]);break;}
            }
    for (int i=1;i<(1<<n);i++)
        for (int j=0;j<n;j++)
        f[i][j].x=1000,f[i][j].i=i,f[i][j].j=j;
    for (int i=0;i<n;i++) f[1<<i][i].x=len[i],f[1<<i][i].s[1]=i,f[1<<i][i].n=1;
    for (int i=1;i<(1<<n);i++)
        for (int j=0;j<n;j++)
        if (i&(1<<j))
            for (int k=0;k<n;k++)
            if (!(i&(1<<k)))
                if (d[j][k]==len[k]) f[i|(1<<k)][j]=min(f[i|(1<<k)][j],f[i][j]),f[i|(1<<k)][j].i=i|(1<<k);
                else
                {
                    data t=f[i][j];
                    f[i][j].x+=len[k]-d[j][k];
                    f[i][j].s[++f[i][j].n]=k;
                    f[i|(1<<k)][k]=min(f[i|(1<<k)][k],f[i][j]),f[i|(1<<k)][k].i=i|(1<<k),f[i|(1<<k)][k].j=k;
                    f[i][j]=t;
                }
    for (int i=1;i<n;i++) f[(1<<n)-1][0]=min(f[(1<<n)-1][0],f[(1<<n)-1][i]),f[(1<<n)-1][0].j=0;
    printf("%s",get((1<<n)-1,0).s+1);
    return 0;
}

 

posted @ 2018-10-17 22:53  Gloid  阅读(182)  评论(0编辑  收藏  举报