本题是一个经典的状压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. c++模板入门

    最近使用了c++模板,觉得非常强大,只是写起来需要掌握一点技巧.大部分模板都是直接把定义写在.h头文件,并且有些人还说这样做的原因是模板不支持分编译,可是以前的编译器对模板的支持不够好吧,但是现在完全 ...

  2. 最小点集覆盖=最大匹配<二分图>/证明

    来源 最小点集覆盖==最大匹配. 首先,最小点集覆盖一定>=最大匹配,因为假设最大匹配为n,那么我们就得到了n条互不相邻的边,光覆盖这些边就要用到n个点. 现在我们来思考为什么最小点击覆盖一定& ...

  3. U3D游戏开发基础

    向量: 1. 向量的长度,即向量的模.计算公式为向量各个分量的平方和,然后开平方. 在D3DX库中,方法为:FLOAT  D3DXVec3Length(CONST  D3DXVECTOR3 * pV) ...

  4. 开源企业管理软件 ONES

    ONES 不是 ONS,基于AngularJS + ThnkPHP开发的企业管理系统平台,名字可以理解为ONES is a Niubility ERP System 或者 ONES Notonly a ...

  5. WiresShark 一站式学习

    按照国际惯例,从最基本的说起. 抓取报文: 下载和安装好Wireshark之后,启动Wireshark并且在接口列表中选择接口名,然后开始在此接口上抓包.例如,如果想要在无线网络上抓取流量,点击无线接 ...

  6. 转 Android开发者指南-Manifest.xml-<supports-screens

    <supports-screens> 版本:Android 3.2 语法: <supports-screensandroid:resizeable=["true" ...

  7. IDL 的读写

    read_ifc代码如下: Write_ifc代码分析如下: (1)将数字转换为字符串的函数. function ntoc,a return,string(a,format='(g0)') end ( ...

  8. 滑雪(ski)

    滑雪(ski) 题目描述 Michael喜欢滑雪.这并不奇怪,因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道 ...

  9. 适用于kali linux的远程桌面开启方法(从windows xp 远程登录到kali linux )

    为了解决Windows远程桌面访问Ubuntu 12.04 之一 中提到的VNC远程桌面的缺点(见http://www.linuxidc.com/Linux/2012-07/64801.htm),我们 ...

  10. LINQ to SQL语句之Union All/Union/Intersect和Top/Bottom和Paging和SqlMethods

    我们继续讲解LINQ to SQL语句,这篇我们来讨论Union All/Union/Intersect操作和Top/Bottom操作和Paging操作和SqlMethods操作 . Union Al ...