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. Spring MVC 3.0.5+Spring 3.0.5+MyBatis3.0.4全注解实例详解(五)

    这是本系列的最后一篇,主要讲一下FreeMarker模板引擎的基本概念与常用指令的使用方式.     一.FreemMarker基本概念     FreemMarker是一个用Java语言编写的模板引 ...

  2. Android_ImageView

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q ...

  3. Web内容禁止选中的两种方式

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/5761818. ...

  4. Fragment碎片频繁来回切换的时候报java.lang.IllegalStateException: No activity

    出现这个问题的原因是因为使用的transcation.replace(fragmentTwo);的方式进行碎片切换的. 解决方案是使用add和show.hide方法组合实现碎片的切换(应该是显示.隐藏 ...

  5. .net+easyui--combobox

    一:预定义结构的 select 元素创建组合框(combobox)值固定写死 <select class="easyui-combobox" name="state ...

  6. magento 常用方法集锦

    1,获得store的配置变量 Mage::getStoreConfig('sectionname/groupname/fields'); 1 Mage::getStoreConfig('section ...

  7. JS操作CSS样式

    一.样式表(css) 使用样式表可以更好的显示WEB文档,也可以结合javascript从而实现很好的控制样式表. 样式(css)与内容(html): HTML是处理文档结构的,HTML可以实现如何把 ...

  8. iOS Crash文件的解析

    iOS Crash文件的解析 开发程序的过程中不管我们已经如何小心,总是会在不经意间遇到程序闪退.脑补一下当你在一群人面前自信的拿着你的App做功能预演的时候,流畅的操作被无情地Crash打断.联想起 ...

  9. MFC设置对话框透明背景

    在对话框初始化函数OnInitDialog函数中添加如下代码: SetWindowLong(GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(GetSafeHwnd(), ...

  10. Scala - 处理时间(nscala-time - Joda Time的scala封装)

    GITHUB : https://github.com/nscala-time/nscala-time MAVEN : (注意选对scala版本) <dependency> <gro ...