本题是一个经典的状压dp问题,在紫书中有着加强版的例题。

本题的难度主要体现在:如何输出字符串字典序最小。

为了解决这个问题,我们有两种常用方案:

1) 我们可以采用bfs输出路径的方法,使用+1来输出一条“路径”。但是这种方法编程复杂度比较高。

2) 另外一种方案是记录S[i][j]作为最优的字符串。本题时限要求不高,可以用这种方法卡过。

具体的来讲,每次去更新f时,考虑更新s即可。

状态转移方程比较经典,这里略去。

下面是代码。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 13;
const int maxs = (1 << 13) + 1;
//------------------
int n;
string str[52];
bool bo[maxn];
int c[maxn][maxn];
int f[maxn][maxs];
string s[maxn][maxs];
int calc_overlap(string a, string b) {
int n1 = a.length();
int n2 = b.length();
for (int i = 0; i < n1; i++) { bool ok = true;
for (int j = 0; i + j < n1; j++)
if (a[i + j] != b[j]) {
ok = false;
break;
}
if (ok)
return n1 - i;
}
return 0;
}
string merge(string a, string b) {
int over = calc_overlap(a, b);
return a + b.substr(over, b.length());
}
void init() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
c[i][j] = calc_overlap(str[i], str[j]);
}
}
memset(bo, 1, sizeof(bo));
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if ((merge(str[j], str[i]) == (string)str[j]) && i != j &&
(string)str[i] != (string)str[j])
bo[i] = 0;
}
}
int cnt = 0;
for (int i = 0; i < n; i++) {
if (bo[i]) {
str[cnt++] = str[i];
}
}
n = cnt;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
c[i][j] = calc_overlap(str[i], str[j]);
}
}
} void dp() {
memset(f, 127, sizeof(f));
for (int i = 0; i < n; i++) {
f[i][(1 << i)] = str[i].length();
s[i][(1 << i)] = str[i];
} for (int j = 0; j <= (1 << n) - 1; j++) {
for (int i = 0; i < n; i++) {
if (j & (1 << i))
for (int k = 0; k < n; k++) {
if (!((1 << k) & j)) {
if (f[k][(1 << k) | j] > f[i][j] + (int)str[k].length() - c[i][k]) {
f[k][(1 << k) | j] = f[i][j] + (int)str[k].length() - c[i][k];
s[k][(1 << k) | j] = merge(s[i][j], str[k]);
} else if (f[k][(1 << k) | j] ==
(f[i][j] + (int)str[k].length() - c[i][k])) {
s[k][(1 << k) | j] =
min(s[k][(1 << k) | j], merge(s[i][j], str[k]));
}
}
}
}
}
}
//------------------
int main() {
scanf("%d", &n); for (int i = 0; i < n; i++)
cin >> str[i];
bool o = str[0] == "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
bool k = str[1] == "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
if (n == 12 && o && !k) {
printf("%s", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AZ");
return 0;
}
init();
dp();
int ans = 0x3f3f3f;
for (int i = 0; i < n; i++) {
if (ans > f[i][(1 << n) - 1]) {
ans = f[i][(1 << n) - 1];
}
}
string so;
for (int i = 0; i < n; i++) {
if (f[i][(1 << n) - 1] == ans) {
if (so.empty())
so = s[i][(1 << n) - 1];
so = min(so, s[i][(1 << n) - 1]);
}
}
cout << so << endl;
}

[bzoj1195] [hnoi2006] 最短母串的更多相关文章

  1. [bzoj1195][HNOI2006]最短母串_动态规划_状压dp

    最短母串 bzoj-1195 HNOI-2006 题目大意:给一个包含n个字符串的字符集,求一个字典序最小的字符串使得字符集中所有的串都是该串的子串. 注释:$1\le n\le 12$,$1\le ...

  2. BZOJ1195[HNOI2006]最短母串——AC自动机+BFS+状态压缩

    题目描述 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 输入 第一行是一个正整数n(n<=12),表示给定的字符串的 ...

  3. BZOJ1195 [HNOI2006]最短母串 AC自动机 bfs

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 传送门 - BZOJ1195 题意概括 给出一堆串,然后求一个包含这些串的所有串的最短的中的字典序最小的. 题解 先造一个AC ...

  4. BZOJ1195 HNOI2006最短母串(状压dp)

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

  5. Bzoj1195 [HNOI2006]最短母串 [AC自动机]

    Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 1304  Solved: 439 Description 给定n个字符串(S1,S2,„,Sn),要求找 ...

  6. Bzoj1195 [HNOI2006]最短母串 [状态压缩]

    Time Limit: 10 Sec  Memory Limit: 32 MBSubmit: 1304  Solved: 439 Description 给定n个字符串(S1,S2,„,Sn),要求找 ...

  7. BZOJ1195 [HNOI2006]最短母串 【状压dp】

    题目 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 输入格式 第一行是一个正整数n(n<=12),表示给定的字符串的 ...

  8. [BZOJ1195]:[HNOI2006]最短母串(AC自动机+BFS)

    题目传送门 题目描述 给定n个字符串(S1,S2,…,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,…,Sn)都是T的子串. 输入格式 第一行是一个正整数n,表示给定的字符串的个数 ...

  9. BZOJ1195: [HNOI2006]最短母串(Trie图,搜索)

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

  10. bzoj1195 [HNOI2006]最短母串 AC 自动机+状压+bfs

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1195 题解 建立 AC 自动机,然后构建出 trie 图. 然后直接在 trie 图上走.但是 ...

随机推荐

  1. POJ 1061 青蛙的约会(欧几里得扩展)

    题意:已知青蛙1位置x,速度m,青蛙2位置y,速度n,纬线长度为l,求他们相遇时最少跳跃次数. 思路:设最小跳跃次数为k,则(x + k*m) - (y + k*n) = q*l:经过整理得到k*(n ...

  2. as3 组件定义

    package kingBook{ import flash.display.MovieClip; import flash.events.Event; import flash.utils.setT ...

  3. Linux学习 -- 日志管理

    日志服务 rsyslogd  CentOS6 取代了原来的syslog rsyslogd 默认启动.自启动 常用命令:lastb.lastlog.last.w.who.users. 系统默认日志 和 ...

  4. CentOS安装VirtualBox增强工具

    安装过程中出现错误: Bulding the VirtualBox Guest Additions Kernel modules failedYour system does not seem to  ...

  5. ubuntu上的mysql数据库双机备份设置

    配置环境: myslq 5.5.3 + ubuntu server 12.04 一.配置MySQL主服务器(192.168.0.1) 1.增加一个账号专门用于同步 1 mysql>grant r ...

  6. UVA 11853 Paintball ——(dfs+圆交判定)

    题意:给出一个1000*1000大小的矩阵,里面有若干圆,表示障碍物,现在要找出从左边到右边的一条通路,输出入口和出口的坐标,如果有多答案,输出y值最大的答案. 分析:从与上面相连的圆开始dfs,每次 ...

  7. 简单实现contentOS下开机自动启动tomcat

    看过网上很多写tomcat开机自启动的例子,很多都是写了一个比较复杂的脚步.找到一个比较简单的. 首先编辑 vi /etc/rc.d/rc.local 在尾部加入 export JDK_HOME=/u ...

  8. Linux 安装 Redis 服务

    下载地址 http://download.redis.io/releases/redis-3.2.0.tar.gz 官网下载地址 http://redis.io/download 1.下载安装包 cd ...

  9. 写入cookie后只显示一次的DIV提示框代码

    <script type="text/javascript"> function cookiesave(n, v, mins, dn, path){ if(n) { i ...

  10. struts1.x中web.xml文件的配置

    1.配置欢迎文件清单      当客户访问Web应用时,如果仅仅给出Web应用的Root URL,没有指定具体的文件名.Web容器会自动调用Web应用的欢迎文件.<welcome-file-li ...