[BZOJ1195] [HNOI2006]最短母串
Description
给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串。
Input
第一行是一个正整数n(n<=12),表示给定的字符串的个数。
以下的n行,每行有一个全由大写字母组成的字符串。每个字符串的长度不超过50.
Output
只有一行,为找到的最短的字符串T。在保证最短的前提下,
如果有多个字符串都满足要求,那么必须输出按字典序排列的第一个。
Sample Input
2
ABCD
BCDABC
ABCD
BCDABC
Sample Output
ABCDABC
我对着一个不满足最优子结构的Dp调了1个多小时,重点是竟然骗了80分哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈。
#include <iostream> #include <cstdio> #include <string> #include <cstring> using namespace std; #define reg register int n; string str[15]; int len[15]; int bin[14]; string f[13][1<<12]; string ans; int main() { bin[0] = 1; for (reg int i = 1 ; i <= 12 ; i ++) bin[i] = bin[i - 1] << 1; scanf("%d", &n); for (reg int i = 1 ; i <= n ; i ++) cin >> str[i], len[i] = str[i].length(); for (reg int i = 1 ; i <= n ; i ++) f[i][bin[i - 1]] = str[i]; // for (reg int i = 1 ; i <= n ; i ++) // { // for (reg int j = 1 ; j <= n ; j ++) // { // if (i == j) continue; // int l1 = len[i], l2 = len[j]; // for (reg int k = max(l1 - l2 + 1, 0) ; k < l1 ; k ++) // { // if (str[i][k] != str[j][0]) continue; // bool ok = 1; // int now = 0; // for (reg int d = k ; d < l1 ; d ++) // if (str[i][d] != str[j][now++]) goto Back; // comb[i][j] = str[i]; // for (reg int d = l1 - k ; d < l2 ; d ++) comb[i][j] += str[j][d]; //// cout<<k<<endl; // break; // Back:; // } //// if (i == 1 and j == 2) system("pause"); // if (comb[i][j] == "") comb[i][j] = str[i] + str[j]; // } // } for (reg int s = 1 ; s <= bin[n] - 1 ; s ++) { for (reg int i = 1 ; i <= n ; i ++) { if (f[i][s] == "") continue; if (!(s & bin[i - 1])) continue; for (reg int j = 1 ; j <= n ; j ++) { if (s & bin[j - 1]) continue; string comb; int l1 = f[i][s].length(), l2 = len[j]; bool Find = 0; for (reg int k = 0 ; k < l1 ; k ++) { int now = 0; for (reg int d = k ; d < l1 and now < l2 ; d ++) if (f[i][s][d] != str[j][now++]) goto End; for (reg int d = l1 - k ; d < l2 ; d ++) comb += str[j][d]; Find = 1; break; End:; } if (!Find) comb = str[j]; if (f[j][s | bin[j - 1]] == "" or f[j][s | bin[j - 1]] > f[i][s] + comb) f[j][s | bin[j - 1]] = f[i][s] + comb; } } } // cout<<f[3][bin[n]-1]<<endl; // cout<<f[2][bin[n]-1]<<endl; // cout << (f[4][bin[n]-1] < f[2][bin[n]-1]) << endl; ans = f[1][bin[n] - 1]; for (reg int i = 2 ; i <= n ; i ++) { if (ans.length() > f[i][bin[n] - 1].length()) ans = f[i][bin[n] - 1]; else if (ans.length() == f[i][bin[n] - 1].length()) ans = min(ans, f[i][bin[n] - 1]); } cout << ans << endl; return 0; }
其实正解是AC自动机加状压DP。
然后不知道为什么写萎了还只有80分,剩下的都RE了,不管了不想调了。
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <queue> using namespace std; #define reg register int n; char str[15][550]; int bin[14]; string ans; char ch[6005]; int nxt[6005][27], tot; int sit[6005], fail[6005]; inline void Insert(char *s, int id) { int now = 0; int len = strlen(s + 1); for (reg int i = 1 ; i <= len ; i ++) { if (nxt[now][s[i] - 'A']) now = nxt[now][s[i] - 'A']; else now = nxt[now][s[i] - 'A'] = ++tot, ch[now] = s[i]; } sit[now] |= bin[id - 1]; } inline void AC_Match() { queue <int> q; for (reg int i = 0 ; i < 26 ; i ++) if (nxt[0][i]) q.push(nxt[0][i]); while(!q.empty()) { int x = q.front();q.pop(); for (reg int i = 0 ; i < 26 ; i ++) { if (nxt[x][i]) fail[nxt[x][i]] = nxt[fail[x]][i], q.push(nxt[x][i]), sit[nxt[x][i]] |= sit[x] | sit[fail[nxt[x][i]]]; else nxt[x][i] = nxt[fail[x]][i]; } } } struct node { int point, situ, now; }; bool vis[605][1<<12]; int pre[60005], top, road[60005]; inline void print(int x) { if (!x) return; print(pre[x]); putchar(road[x] + 'A'); } inline void bfs() { queue <node> q; int nn = 0; q.push((node){0, sit[0], 0}); vis[0][sit[0]] = 1; while(!q.empty()) { int x = q.front().point, situ = q.front().situ, id = q.front().now; q.pop(); if (situ == bin[n] - 1) { print(id); return ; } for (reg int i = 0 ; i < 26 ; i ++) { int nt = situ | sit[nxt[x][i]]; if (!nxt[x][i]) continue; if (vis[nxt[x][i]][nt]) continue; vis[nxt[x][i]][nt] = 1; pre[++nn] = id, road[nn] = i; q.push((node){nxt[x][i], nt, nn}); } } } int main() { bin[0] = 1; for (reg int i = 1 ; i <= 12 ; i ++) bin[i] = bin[i - 1] << 1; scanf("%d", &n); for (reg int i = 1 ; i <= n ; i ++) scanf("%s", str[i] + 1), Insert(str[i], i); AC_Match(); bfs(); return 0; }