zoukankan      html  css  js  c++  java
  • Bzoj1195 [HNOI2006]最短母串 [状态压缩]

    Time Limit: 10 Sec  Memory Limit: 32 MB
    Submit: 1304  Solved: 439

    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自动机+BFS:http://www.cnblogs.com/SilverNebula/p/6445516.html

    状压DP+神(bao)奇(li)预处理

    先找出所有被其他串包含的串并扔掉(显然)

    暴力预处理出每两个串连接起来,公共部分的长度。

    进行状压DP,暴力储存每个状态对应的字符串。

    在所有的11111...的最终状态中,暴力找出字典序最小的那个

    是不是很神(bao)奇(li)?

    不知道为何,用strcmp会TLE(也可能是别的处理不到位),各处优化了一下,手写了比较函数,终于过了

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<queue>
     6 using namespace std;
     7 const int INF=0x3f3f3f3f;
     8 const int mxn=61;
     9 int n;
    10 struct bind{
    11     char s[605];
    12     int len;
    13     bool operator < (const bind y) const {
    14         if(len!=y.len)return len<y.len;
    15         for(int i=0;i<len;i++)
    16             if(s[i]!=y.s[i])return s[i]<y.s[i];
    17         return 0;
    18     }
    19 }f[1<<12][12],s[12];
    20 int c[13][13];
    21 bool ban[mxn];
    22 
    23 bool ovl(int i,int j){//判断能否覆盖 
    24     if(s[i].len<s[j].len)return 0;
    25     char *p=strstr(s[i].s,s[j].s);
    26     if(p==NULL)return 0;
    27     return 1;
    28 }
    29 int clc(int x,int y){//统计共用串长度 
    30     bool flag=0;
    31     for(int i=max(0,s[x].len-s[y].len);i<s[x].len;i++){
    32         flag=1;
    33         for(int j=i;j<s[x].len;j++)
    34             if(s[x].s[j]!=s[y].s[j-i]){flag=0;break;}
    35         if(flag)return s[x].len-i;//--1
    36     }
    37     return 0;
    38 }
    39 bind merge(int S,int u,int v){//字符串合并 
    40     bind tmp=f[S][u];
    41     strcat(tmp.s,s[v].s+c[u][v]);
    42     tmp.len=f[S][u].len-c[u][v]+s[v].len;
    43 //    printf("merge:%d %d %d :%d
    ",S,u,v,tmp.len);
    44     return tmp;
    45 }
    46 void Dp(){
    47     int i,j,ed=(1<<n)-1;
    48     for(i=0;i<=ed;i++)
    49         for(j=0;j<n;j++)f[i][j].len=INF;//init
    50     for(i=0;i<n;i++)f[1<<i][i]=s[i];
    51     for(i=1;i<=ed;i++){
    52         for(j=0;j<n;j++){
    53             if((i>>j)&1)
    54                 for(int k=0;k<n;k++){
    55                     if((i>>k)&1)continue;
    56                     bind tmp=merge(i,j,k);
    57                     if(tmp<f[i|(1<<k)][k])f[i|(1<<k)][k]=tmp;
    58                 }
    59         }
    60     }
    61 }
    62 int main(){
    63     int i,j;
    64     scanf("%d",&n);
    65     for(i=0;i<n;i++)scanf("%s",s[i].s),s[i].len=strlen(s[i].s);
    66     for(i=0;i<n;i++)
    67         for(j=0;j<n;j++)
    68             if(i!=j && ovl(i,j) && !ban[i])ban[j]=1;
    69     int cnt=0;
    70     for(i=0;i<n;i++)if(!ban[i])s[cnt++]=s[i];
    71     n=cnt;
    72     for(i=0;i<n;i++)
    73         for(j=0;j<n;j++)
    74             if(i!=j)c[i][j]=clc(i,j);
    75     Dp();
    76     int ans=0,ed=(1<<n)-1;
    77     for(i=1;i<n;i++)
    78         if(f[ed][i]<f[ed][ans])ans=i;
    79     printf("%s",f[ed][ans].s);
    80     return 0;
    81 }
  • 相关阅读:
    常见WINDOWS运行命令
    CSDN Blog 之七宗罪
    常见进程大全
    开始→运行→输入的命令集锦(网上搜来的)
    20200527:SpringCloud用了那些组件?分布式追踪链怎么做的?熔断器工作原理?
    20200520:分库分表后如何迁移?
    20200523:如何实现并发限流
    20200521:es底层读写原理?倒排索引原理?
    20200525:MQ应用场景、Kafka和rabbit区别?kafka为什么支撑高并发? 来自
    20200519:催收核心业务是什么?
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6445487.html
Copyright © 2011-2022 走看看