[bzoj1195] [hnoi2006] 最短母串
本题是一个经典的状压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] 最短母串的更多相关文章
- [bzoj1195][HNOI2006]最短母串_动态规划_状压dp
最短母串 bzoj-1195 HNOI-2006 题目大意:给一个包含n个字符串的字符集,求一个字典序最小的字符串使得字符集中所有的串都是该串的子串. 注释:$1\le n\le 12$,$1\le ...
- BZOJ1195[HNOI2006]最短母串——AC自动机+BFS+状态压缩
题目描述 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 输入 第一行是一个正整数n(n<=12),表示给定的字符串的 ...
- BZOJ1195 [HNOI2006]最短母串 AC自动机 bfs
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 传送门 - BZOJ1195 题意概括 给出一堆串,然后求一个包含这些串的所有串的最短的中的字典序最小的. 题解 先造一个AC ...
- BZOJ1195 HNOI2006最短母串(状压dp)
按照子串出现的先后考虑.令f[i][j]为已经出现的字符串集合为i,最后一个出现的字符串为j时的最短串长,预处理一下任意两个串的最长重叠长度,转移显然.有点麻烦的是字典序,强行增加代码难度. 另一个比 ...
- Bzoj1195 [HNOI2006]最短母串 [AC自动机]
Time Limit: 10 Sec Memory Limit: 32 MBSubmit: 1304 Solved: 439 Description 给定n个字符串(S1,S2,„,Sn),要求找 ...
- Bzoj1195 [HNOI2006]最短母串 [状态压缩]
Time Limit: 10 Sec Memory Limit: 32 MBSubmit: 1304 Solved: 439 Description 给定n个字符串(S1,S2,„,Sn),要求找 ...
- BZOJ1195 [HNOI2006]最短母串 【状压dp】
题目 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 输入格式 第一行是一个正整数n(n<=12),表示给定的字符串的 ...
- [BZOJ1195]:[HNOI2006]最短母串(AC自动机+BFS)
题目传送门 题目描述 给定n个字符串(S1,S2,…,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,…,Sn)都是T的子串. 输入格式 第一行是一个正整数n,表示给定的字符串的个数 ...
- BZOJ1195: [HNOI2006]最短母串(Trie图,搜索)
Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. Input 第一行是一个正整数n(n<=12) ...
- bzoj1195 [HNOI2006]最短母串 AC 自动机+状压+bfs
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1195 题解 建立 AC 自动机,然后构建出 trie 图. 然后直接在 trie 图上走.但是 ...
随机推荐
- VS2010 自定义向导
最近在学OpenGL,不想使用OpenGL的GLUT工具,自己写了一个初始化OpenGL的类,并在win32中使用,每次都要新建一个win32项目,然后将OpenGL初始化类拷贝到项目,然后进行各种初 ...
- PostConstruct注解
应用场景:当你需要往Bean里注入一个其父类中定义的属性,而你又无法复写父类的属性或属性的setter方法时 public class UserDaoImpl extends HibernateDao ...
- 最简单的epoll的使用范例 : 监听 标准输入 ,并将数据回显到终端
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/epoll.h> # ...
- 测试redis+keepalived实现简单的主备切换【转载】
转自: 测试redis+keepalived实现简单的主备切换 - Try My Best 尽力而为 - ITeye技术网站http://raising.iteye.com/blog/2311757 ...
- 2016大连网络赛 Football Games
Football Games Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) P ...
- OpenGL学习--------动画制作
假设某动画一共有n幅画面,则它的工作步骤就是:显示第1幅画面,然后等待一小段时间,直到下一个1/24秒显示第2幅画面,然后等待一小段时间,直到下一个1/24秒……显示第n幅画面,然后等待一小段时间,直 ...
- eclipse工程名出现小红叉的解决办法
前提是eclipse工程中每个子文件都没错,工程名上却显示了小红叉. 打开[Window]->[Show View]->[General]->[Problems],看看Problem ...
- decoder3_8
这两天回归书本,继续阅读书上的内容,此时的体会与刚开始学那会的体会是不一样的,比如3_8decoder,之前就认为可以用case来写,而书上有一种更简便的方式来描述,带给你新的思路,既然有新方式可以描 ...
- 关于nodejs的require顺序
--------------------------------------- check /home/somebody/node_modules/othermodule check /home/so ...
- HDU 3652(数位DP)
题目链接:B-number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tot ...