本题是一个经典的状压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. iOS 开发中的各种证书

    公钥和私钥 转载自:http://www.samirchen.com/ios-certificates/ 先简单的介绍一下公钥和私钥.我们常见的加密算法有两类:对称加密算法(Symmetric Cry ...

  2. android touchEvent事件学习

    学习网址:http://www.apkbus.com/forum.php?mod=viewthread&tid=44296 1:Android Touch事件传递机制解析 android系统中 ...

  3. 转:透析QTP自动化测试框架SAFFRON

    1.为什么要使用框架? 框架是一组自动化测试的规范.测试脚本的基础代码,以及测试思想.惯例的集合.可用于减少冗余代码.提高代码生产率.提高代码重用性和可维护性.例如QTestWare就是QTP自动化测 ...

  4. play1.x vs play2.x 对比(转)

    个人看到对比play1.x和play2.x比较的文章中,写的最深入,最清晰的一个.转自:http://freewind.me/blog/20120728/965.html 为了方便群中的Play初学者 ...

  5. UVALive 6887 Book Club

    最大流,有向环覆盖问题. #include<cstdio> #include<cstring> #include<string> #include<cmath ...

  6. MySQL常用命令总结2

    USE db_name; //使用(打开)数据库 SELECT DATABASE(); //查看当前打开的数据库 CREATE TABLE tb_name( column_name data_type ...

  7. dfs和bfs的简单总结

    首先是dfs,又名深度优先搜索.看名字就知道,它的核心思想就是一直搜索,先在一条路上面一路撸到底,如果到底没有办法前进了,那么判断是否到达终点,如果没有到达,那么就回溯到之前的点再撸. dfs的要点: ...

  8. CF 365 div2 D

    http://codeforces.com/contest/703/problem/D 题目大意:给你一个长度为n数组,有q个询问,每次询问一个区间[l,r],这个区间的val就是所有数值为偶数个的数 ...

  9. AXIS-web.xml里配置axis报错addChild: Child name 'AxisServlet' is not unique 解决办法

    报错这个那么就表示,web.xml中有相同的AxisServlet的这个名字,可以把原来的删除配置自己的,也可以保留原来的,自己的不配置 Ctrl+f 搜索下就知道了

  10. android脚步---如何看log之程序停止运行,和UI线程和非UI线程之间切换

    经常运行eclipse时,烧到手机出现,“停止运行”,这时候得通过logcat查log了.一般这种情况属于FATAL EXCEPTION,所以检索FATAL 或者 EXCEPTION,然后往下看几行 ...