1195: [HNOI2006]最短母串

Time Limit: 10 Sec  Memory Limit: 32 MB
Submit: 894  Solved: 288
[Submit][Status][Discuss]

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
 
 
  本来高高兴兴写了个DP,然而发现根本无法解决字典序问题,怎么办能?
  搜吧。。。。。
  我们假设已经正确地写出了DP,从而得出了答案的长度以及一个字典序不怎么优的解,我们还是dfs枚举顺序,保证当前枚举字符串的字典序小于答案。
  一个强剪枝:如果当前所有没有选的串的“最少选择增加量”之和加上当前字符串长度大于答案直接break
  然后就过了。。。。
  maya,以后这类DP题我都会做了!
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<cassert>
using namespace std;
#define MAXN 13
#define MAXS 55
#define INF 0x3f3f3f3f
char str[][];
string res;
int bstans=INF;
namespace task1
{
string str[MAXN];
char ss[MAXN][MAXS];
int len[MAXN];
int dis[MAXN][MAXN];
int dp[MAXN][<<];
int rec[MAXN][<<][];
char res[MAXN*MAXS];
void deal(int &x,int y)
{
if (x>y)x=y;
}
bool cmp_str(const string& s1,const string &s2)
{
for (int i=;i<=min(s1.length(),s2.length());i++)
{
if (s1[s1.length()-i]!=s2[s2.length()-i])return s1[s1.length()-i]<s2[s2.length()-i];
}
return false;
}
int main(int n)
{
int m,i,j,k1,k2,k;
int x,y;
for (i=;i<n;i++)
{
str[i]=::str[i];
}
for (j=;j<n;j++)
for (i=;i<n;i++)
if (i!=j && str[i].find(str[j])!=-)
{
swap(str[n-],str[j]);
str[--n]="";
j--;
break;
}
sort(str,&str[n],cmp_str);
for (i=;i<n;i++)
len[i]=str[i].length(),strcpy(ss[i],str[i].c_str());
// memset(dis,INF,sizeof(dis));
for (i=;i<n;i++)
{
for (j=;j<n;j++)
{
if (i==j)continue;
dis[i][j]=len[j];
for (k1=;k1<len[i];k1++)
{
bool flag=true;
for (k2=;k2+k1<len[i] && k2<len[j];k2++)
{
if (ss[i][k1+k2]!=ss[j][k2])
{
flag=false;
break;
}
}
if (flag)
{
dis[i][j]=max(,-(len[i]-k1)+len[j]);
break;
}
}
}
}
memset(dp,INF,sizeof(dp));
for (i=;i<n;i++)
dp[i][<<i]=len[i];
int ii;
for (ii=;ii<n;ii++)
{
for (k=;k<n;k++)
{
for (j=;j<(<<n);j++)
{
if (__builtin_popcount(j)!=ii)continue;
for (i=;i<n;i++)
{
if (dp[i][j]==INF)continue;
if ((j&(<<k))==)
{
if (dp[k][j|(<<k)]>dp[i][j]+dis[i][k])
{
dp[k][j|(<<k)]=dp[i][j]+dis[i][k];
rec[k][j|(<<k)][]=i;
rec[k][j|(<<k)][]=j;
}
}
}
}
}
}
int ans=INF;
for (i=;i<n;i++)
if (ans>dp[i][(<<n)-])
{
ans=dp[i][(<<n)-];
x=i;
y=(<<n)-;
}
vector<int> vec;
int xx,yy;
for (i=;i<n;i++)
{
vec.push_back(x);
xx=x;yy=y;
x=rec[xx][yy][];
y=rec[xx][yy][];
}
for (int i=;i<vec.size()/;i++)
swap(vec[i],vec[vec.size()--i]);
strcat(res,ss[vec[]]);
for (i=;i<vec.size();i++)
{
strcat(res,ss[vec[i]]+len[vec[i]]-dis[vec[i-]][vec[i]]);
}
::res=res;
::bstans=ans;
}
}
int cst[][];
int len[];
bool bad[];
string curs;
int cnt;
int n;
bool cmp_pair(pair<char*,int> p1,pair<char*,int> p2)
{
return strcmp(p1.first,p2.first)<;
}
int mncst[];
int dfs(int now,int status,int tdis,int cnt)
{
if (tdis>bstans)return ;
if (curs>res)return ;
int t=,ret=;
for (int i=;i<n;i++)
{
if (!(status&(<<i)))
{
t+=mncst[i];
}
}
if (t+tdis>bstans)
return ;
if (status==(<<n)-)
{
if (bstans>tdis)
{
assert(false);
res=curs;
bstans=tdis;
}else
{
res=min(res,string(curs));
}
return ;
}
pair<char *,int> seq[];
int tots=;
for (int i=;i<n;i++)
if (!(status&(<<i)))
seq[tots++]=make_pair(str[i] + len[i]-cst[now][i],i);
sort(seq,seq+tots,cmp_pair);
for (int i=;i<tots;i++)
{
curs+=str[seq[i].second]+(len[seq[i].second]-cst[now][seq[i].second]);
t=dfs(seq[i].second,status|(<<seq[i].second),tdis+cst[now][seq[i].second],cnt*/tots);
cnt-=t;
ret+=t;
curs=curs.substr(,tdis);
//if (cnt<=0)break;
}
return ret;
} int main()
{
// freopen("input.txt","r",stdin);
int x,y,z;
scanf("%d",&n);
for (int i=;i<n;i++)
{
scanf("%s",str[i]);
len[i]=strlen(str[i]);
}
task1::main(n);
for (int i=;i<n;i++)
{
if (bad[i])continue;
for (int j=;j<n;j++)
{
if (i==j)continue;
for (int k=;k<len[i];k++)
{
bool flag2=false;
for (int k2=;k+k2<len[i];k2++)
{
if (str[i][k2+k]!=str[j][k2])
{
break;
}
if (k2==len[j]-)
{
flag2=true;
break;
}
}
if (flag2)
bad[j]=true;
}
}
}
x=;
for (int i=;i<n;i++)
{
if (!bad[i])
strcpy(str[x++],str[i]);
}
n=x;
char tmp[];
for (int i=;i<n;i++)
for (int j=i;j<n;j++)
if (string(str[i])>string(str[j]))
{
strcpy(tmp,str[i]);
strcpy(str[i],str[j]);
strcpy(str[j],tmp);
}
for (int i=;i<n;i++)
len[i]=strlen(str[i]);
for (int i=;i<n;i++)
{
for (int j=;j<n;j++)
{
if (i==j)continue;
for (int k=;k<=len[i];k++)
{
bool flag=true;
for (int k2=;k2+k<len[i];k2++)
{
if (str[i][k2+k]!=str[j][k2])
{
flag=false;
break;
}
}
if (flag)
{
cst[i][j]=len[j]-(len[i]-k);
break;
}
}
}
}
for (int i=;i<n;i++)
{
int x=INF;
for (int j=;j<n;j++)
{
if (i==j)continue;
x=min(x,cst[j][i]);
}
mncst[i]=x;
}
for (int i=;i<n;i++)
{
curs=str[i];
dfs(i,<<i,len[i],);
}
cout<<res<<endl;
}

bzoj 1195: [HNOI2006]最短母串 爆搜的更多相关文章

  1. BZOJ 1195: [HNOI2006]最短母串

    1195: [HNOI2006]最短母串 Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 1346  Solved: 450[Submit][Status ...

  2. bzoj 1195 [HNOI2006]最短母串 bfs 状压 最短路 AC自动机

    LINK:最短母串 求母串的问题.不适合SAM. 可以先简化问题 考虑给出的n个字符串不存在包含关系. 那么 那么存在的情况 只可能有 两个字符串拼接起来能表示另外一个字符串 或者某个字符串的后缀可以 ...

  3. 【刷题】BZOJ 1195 [HNOI2006]最短母串

    Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12) ...

  4. BZOJ 1195 [HNOI2006]最短母串 (Trie图+状压+bfs最短路)

    BZOJ1195 LOJ10061 题目大意:给你$n$个模式串,求一个最短且字典序最小的文本串并输出这个串,$n<=12,len<=50$ 首先对所有模式串构造$Trie$图,$Trie ...

  5. bzoj 1195: [HNOI2006]最短母串【状压dp】

    我有病吧--明明直接枚举是否匹配就可以非要写hash,然后果然冲突了(--我个非酋居然还敢用hash 设f[s][i]为已选串状态为s并且最后一个串是i,还有预处理出g[i][j]表示最长有长为g[i ...

  6. BZOJ 1195: [HNOI2006]最短母串 AC自动机+状压+搜索

    思路比较直接. 由于 $n$ 很小,直接定义 $f[i][j]$ 表示当前在自动机中的节点 $i,$ 被覆盖串的集合为 $j$ 的方案数. #include <bits/stdc++.h> ...

  7. 【状态压缩dp】1195: [HNOI2006]最短母串

    一个清晰的思路就是状压dp:不过也有AC自动机+BFS的做法 Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T ...

  8. 1195: [HNOI2006]最短母串 - BZOJ

    Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串.Input 第一行是一个正整数n(n<=12), ...

  9. 1195: [HNOI2006]最短母串

    思路:好像以前谁问过我这题...  状个压就好啦, 把包含在其他串中的字符串删掉, 预处理除每两个字符串之间的关系, dp[ state ][ i ] 表示在state的状态下, 最后一个字符串是第i ...

随机推荐

  1. Copy-On-Write技术 (摘录)

    Copy-On-Write技术     Copy-On-Write是写时才copy的意思,有延迟操作的意思在里面.比如往磁盘写数据,先写到的是内存里面,只有文件close或flush时才真正写到磁盘. ...

  2. Android开发之玩转FlexboxLayout布局

    在这之前,我曾认真的研究过鸿洋大神的Android 自定义ViewGroup 实战篇 -> 实现FlowLayout,按照大神的思路写出了一个流式布局,所有的东西都是难者不会会者不难,当自己能自 ...

  3. 详解ExplosionField的使用,实现View的粉碎效果

    小米平板卸载软件的时候,会有一个粉碎的效果,看起来很拉风,GitHub上有一个开源控件可以实现这个效果,我们一起来看看.先来看看效果图: 看起来不错吧,那我们今天就来详细说说ExplosionFiel ...

  4. oh-my-zsh配置 alias 指定指令别名

    # vim ~/.zshrc alias ydocx="/Users/wanglili/work/mfe/ydoc/bin/ydoc" # source ~/.zshrc

  5. arcmap10如果判断一个面是否含洞

    使用字段计算器,使用python !Shape.isMultipart!结果为true就是,false不是

  6. iOS 并行编程:NSOperation Queues

    1 简介 1.1 功能        Operation Queue也是IOS的一种并行编程技术,类似Dispatch Queue可以帮助用户管理多线程.但是Operation Queue将任务封装在 ...

  7. Scala应用函数

    我们使用“_” 来代替单个的参数,实际上你也可以使用“_”来代替整个参数列表,比如说,你可以使用 print _ 来代替 println (_). someNumbers.foreach(printl ...

  8. 你不知道的javascript 上卷 读书笔记

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. linux的终端,网络虚拟终端,伪终端(转)

    转自http://www.xuebuyuan.com/877887.html 2013年09月07日 ⁄ 综合 ⁄ 共 4047字 ⁄ 字号 小 中 大 ⁄ 评论关闭 Linux上许多网络服务应用,如 ...

  10. webform 转 MVC 飞一般的感觉

    前言: 浅谈webform与mvc,让开发变得更加简单,这里主要通过比较webform与mvc的开发方式,以下全属个人看法,不完善的地方可以留言补充. 正文: 废话不多说,直接说工作中经常用到的地方 ...