• 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
    ";
    #else
        const char LL[]="%lld
    ";
    #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;
    }
  • 相关阅读:
    微软企业库调用Oracle存储过程返回(1个或多个)数据集
    (转)Oracle表空间
    HTML5操作
    完美实现 ASP.NET 2.0 中的URL重写伪静态(映射) &gt;(转载)的简介与内容
    HTML5 audio 详解
    步步为营:Asp.Net使用HttpWebRequest通知,抓取,采集(转)
    js cookie操作
    多线线程
    js with用法
    asp.net AllowSorting="true"仍然不能排序的原因
  • 原文地址:https://www.cnblogs.com/Gloid/p/9807729.html
Copyright © 2020-2023  润新知