Luogu 2322 [HNOI2006]最短母串问题
唔,太菜了,弄了好几个小时。
状压dp,设$f_{s, i}$表示选了集合$s$,以$i$结尾的最短长度,设$g_{i, j}$表示串$i$的后缀和串$j$的前缀的最长匹配长度。
$f_{s, i} + len_{j} - g_{i, j} $ 可以转移到$f_{s | (1 << (j - 1)), j}$ $(i\in s, j\notin s)$。
转移的时候发现两个串的长度一样要把这两个的答案都弄出来比一比字典序。
如果一个串是另一个串的字串,不参与转移。
注意特判全部串相同的情况。
可以用kmp优化$g$的计算和判断子串,但是$n$太小了,所以时间并不会差太多。
时间复杂度$O(能过)$。
用AC自动机 + BFS转移会更优美.
Code:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int N = ;
const int S = ( << ) + ;
const int L = ;
const int inf = 0x3f3f3f3f; int n, nowLen, len[N], g[N][N], f[S][N], pre[S][N];
bool mark[N]; struct MyStr {
char s[L];
} a[N]; inline void chkMin(int &x, int y) {
if(y < x) x = y;
} inline bool chk(int x, int y, int l) {
for(int i = len[x] - l + , j = ; j <= l; i++, j++)
if(a[x].s[i] != a[y].s[j]) return ;
return ;
} inline bool con(char *s1, int y) {
char *s2 = a[y].s;
if(len[y] > nowLen) return ;
for(int i = ; i <= nowLen; i++)
if(s1[i] == s2[]) {
bool flag = ;
for(int k = i + , j = ; j <= len[y]; j++, k++)
if(s2[j] != s1[k]) {
flag = ;
break;
}
if(flag) return ;
}
return ;
} inline void getS(int nowS, int now, char *str) {
if(!pre[nowS][now]) {
nowLen = ;
for(int i = ; i <= len[now]; i++)
str[++nowLen] = a[now].s[i];
return;
}
if(pre[nowS][now]) getS(nowS ^ ( << (now - )), pre[nowS][now], str);
// if(con(str, now)) return;
for(int i = g[pre[nowS][now]][now] + ; i <= len[now]; i++)
str[++nowLen] = a[now].s[i];
} inline bool myCmp(char *s1, char *s2, int l) {
for(int i = ; i <= l; i++)
if(s1[i] < s2[i]) return ;
else if(s1[i] > s2[i]) return ;
return ;
} int main() {
scanf("%d", &n);
for(int i = ; i <= n; i++) scanf("%s", a[i].s + );
// sort(a + 1, a + 1 + n, cmp);
for(int i = ; i <= n; i++) len[i] = strlen(a[i].s + ); for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++) {
if(i == j) {
g[i][j] = len[i];
continue;
}
for(int k = min(len[i], len[j]); k >= ; k--)
if(chk(i, j, k)) {
g[i][j] = k;
break;
}
} for(int i = ; i <= n; i++) {
nowLen = len[i];
for(int j = ; j <= n; j++) {
if(j == i) continue;
if(con(a[i].s, j)) mark[j] = ;
}
} bool flag = ;
for(int i = ; i <= n; i++)
if(!mark[i]) {
flag = ;
break;
}
if(!flag) {
puts(a[].s + );
return ;
} /* printf("\n");
for(int i = 1; i <= n; i++)
printf("%s\n", a[i].s + 1);
printf("\n");
for(int i = 1; i <= n; i++, printf("\n"))
for(int j = 1; j <= n; j++)
printf("%d ", g[i][j]); */ memset(f, 0x3f, sizeof(f));
for(int i = ; i <= n; i++)
if(!mark[i]) f[ << (i - )][i] = len[i]; char str1[N * L], str2[N * L];
for(int s = ; s < ( << n); s++)
for(int i = ; i <= n; i++)
if((s & ( << (i - ))) && f[s][i] != inf && !mark[i])
for(int j = ; j <= n; j++)
if(!(s & ( << (j - ))) && !mark[j]) {
// getS(s, i, str1);
int now = len[j] - g[i][j];
if(f[s][i] + now < f[s | ( << (j - ))][j]) {
f[s| ( << (j - ))][j] = now + f[s][i];
pre[s| ( << (j - ))][j] = i;
} else if(f[s][i] + now == f[s | ( << (j - ))][j]) {
getS(s | ( << (j - )), j, str1), getS(s, i, str2);
for(int k = g[i][j] + ; k <= len[j]; k++)
str2[++nowLen] = a[j].s[k]; if(myCmp(str2, str1, nowLen)) pre[s | ( << (j - ))][j] = i;
}
} int ans = inf, curS = ( << n) - ;
for(int i = ; i <= n; i++)
if(mark[i]) curS ^= ( << (i - ));
for(int i = ; i <= n; i++)
chkMin(ans, f[curS][i]); int pos = ;
for(int i = ; i <= n; i++)
if(f[curS][i] == ans) {
getS(curS, i, str1);
pos = i;
break;
} for(int i = pos + ; i <= n; i++) {
if(f[curS][i] > ans) continue;
getS(curS, i, str2); /* for(int j = 1; j <= ans; j++) putchar(str1[j]); printf("\n");
for(int j = 1; j <= ans; j++) putchar(str2[j]); printf("\n"); */ if(myCmp(str2, str1, ans))
for(int j = ; j <= ans; j++) str1[j] = str2[j];
} for(int i = ; i <= ans; i++)
putchar(str1[i]);
printf("\n");
return ;
}
Luogu 2322 [HNOI2006]最短母串问题的更多相关文章
- bzoj 1195: [HNOI2006]最短母串 爆搜
1195: [HNOI2006]最短母串 Time Limit: 10 Sec Memory Limit: 32 MBSubmit: 894 Solved: 288[Submit][Status] ...
- 2782: [HNOI2006]最短母串
2782: [HNOI2006]最短母串 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 3 Solved: 2[Submit][Status][Web ...
- BZOJ 1195: [HNOI2006]最短母串
1195: [HNOI2006]最短母串 Time Limit: 10 Sec Memory Limit: 32 MBSubmit: 1346 Solved: 450[Submit][Status ...
- P2322 [HNOI2006]最短母串问题
P2322 [HNOI2006]最短母串问题 AC自动机+bfs 题目要求:在AC自动机建的Trie图上找到一条最短链,包含所有带结尾标记的点 因为n<12,所以我们可以用二进制保存状态:某个带 ...
- [HNOI2006]最短母串问题 --- AC自动机 + 隐式图搜索
[HNOI2006]最短母串问题 题目描述: 给定n个字符串(S1,S2.....,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,......,Sn)都是T的子串. 输入格式: 第 ...
- 【状态压缩dp】1195: [HNOI2006]最短母串
一个清晰的思路就是状压dp:不过也有AC自动机+BFS的做法 Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T ...
- BZOJ_1195_[HNOI2006]最短母串_AC自动机+BFS+分层图
BZOJ_1195_[HNOI2006]最短母串_AC自动机+BFS+分层图 Description 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2, ...
- [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),表示给定的字符串的 ...
随机推荐
- 微信浏览器HTTP_USER_AGENT判断
微信公众平台开发 微信公众平台开发者 微信公众平台开发模式 微信浏览器 HTTP_USER_AGENT作者:方倍工作室 原文:http://www.cnblogs.com/txw1958/archiv ...
- KVM- 日常管理与配置
KVM虚拟机的管理主要是通过virsh命令对虚拟机进行管理. 1. 查看KVM虚拟机配置文件及运行状态 (1) KVM虚拟机默认配置文件位置: /etc/libvirt/qemu/ autostar ...
- 201621123014《Java程序设计》第十四周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结与数据库相关内容. 2. 使用数据库技术改造你的系统 2.1 简述如何使用数据库技术改造你的系统.要建立什么表?截图你的表设计. 答 ...
- 细说移动前端Android联调
为什么要联调 A:正在疯狂coding的时候,产品MM过来,焦急的说两周前的一个页面在手机上显示略微错位,但小本上显示正常! B:本着爱折腾的原则,作为大前端,在移动互联网时代的基本技能. 联调的方式 ...
- bzoj4513 储能表
求 $\sum\limits_{i=0}^{n-1} \sum\limits_{j=0}^{m-1} max((x \space xor \space j) - k,0)$ ,膜 $p$ $n,m \ ...
- BZOJ- 2733: 永无乡 (并查集&线段树合并)
题意:给定N个节点,K次操作,操作有两种,1是合并两个集合,2是求某个集合的第K大(从小到大排序). 思路:合并只要启发式即可.此题可以用线段树,保存1到N的排序的出现次数和. 复杂度O(NlogN) ...
- Linux命令学习(20):traceroute命令
版权声明 更新:2017-06-13博主:LuckyAlan联系:liuwenvip163@163.com声明:吃水不忘挖井人,转载请注明出处! 1 文章介绍 本文介绍了Linux下面的mv命令. 2 ...
- ECMAScript6入门-序言
本系列笔记基于阮一峰大佬的开源书籍.如果大家想看可以去该地址 本系列笔记只记录本人自己学习的过程,如果有侵权收到通知会自行下架. 如果大家看到可以直接去地址处学习,如果觉得好还望支持正版. 在此感谢阮 ...
- 二:HTML文本编译器 kindeditor-4.1.10 的使用 SpringMVC+jsp的实现
这和一篇与上一篇的区别在与,上一篇是直接请求到action我们剩下的都是我们全部手动处理, 而这一片篇是由kindeditor内部处理,图片上传到本地,基本上没什么区别,但是有一点一定要注意的就是,这 ...
- CPU 和 Linux 进程
进程与线程 进程应该是Linux中最重要的一个概念.进程运行在CPU上,是所有硬件资源分配的对象.Linux中用一个task_struct的结构来描述进程,描述了进程的各种信息.属性.资源. Linu ...