BZOJ1195 : [HNOI2006]最短母串
用最短方案中字典序最小的字符串包含所有给定字符串
看空间比较小就写状压了
好像直接bfs也行
然而这是一种状压dp的做法
设 f[s][i] 为当前在 AC自动机 上编号为 i 的节点,已选择过的字符串集合为 s 的状态
直接大力转移即可
转移到的第一个选择了全集的 s 的时候直接退出 输出方案
由于要输出方案,需要对每个状态记录它的 pre状态 和转移过来的 pre节点,这样方便输出
因为在 AC自动机 上是按字典序枚举的
这样好像就跟搜索差不多了
完整代码:
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cctype> #include<cstdio> #include<queue> using namespace std; typedef long long ll; const int MAXN = 15, MAXL = 55; struct Node{ short nxt[26], tag, curchar; Node() {memset(nxt, 0, sizeof(nxt)); tag = 0;} }t[MAXL * MAXN]; struct DP{ short len, preS, preNo; DP(short lenth = 0, short prestt = 0, short prenum = 0) {len = lenth; preS = prestt; preNo = prenum;} }f[(1 << 12)][MAXL * MAXN]; short n, ptr, Root, dst, top; short fail[MAXN * MAXL], stk[MAXN * MAXL]; char str[MAXL]; bool vis[(1 << 12)][MAXL * MAXN]; inline short newnode() { return ++ptr; } inline void Insert(char *s, short No) { short len = strlen(s), cur = Root; for(short i = 0; i < len; ++i) { register short x = s[i] - 'A'; if(!t[cur].nxt[x]) { t[cur].nxt[x] = newnode(); t[t[cur].nxt[x]].curchar = s[i]; } cur= t[cur].nxt[x]; } t[cur].tag |= (1 << (No - 1)); return; } inline void getfail() { queue<short> q; short cur = Root; for(short i = 0; i < 26; ++i) { if(t[cur].nxt[i]) { q.push(t[cur].nxt[i]); fail[t[cur].nxt[i]] = 0; } } while(!q.empty()) { short cur = q.front(); q.pop(); for(short i = 0; i < 26; ++i) { register short son = t[cur].nxt[i]; if(!t[cur].nxt[i]) { t[cur].nxt[i] = t[fail[cur]].nxt[i]; continue; } fail[son] = t[fail[cur]].nxt[i]; t[son].tag |= t[fail[son]].tag; q.push(son); } } return; } inline DP dp() { queue<pair<short, short> > q; short cur = Root, s = 0; q.push(make_pair(cur, s)); f[s][cur].len = 0; while(!q.empty()) { cur = q.front().first; s = q.front().second; q.pop(); for(short i = 0; i < 26; ++i) { register short son = t[cur].nxt[i]; if(t[son].tag && ((s | t[son].tag) != s)) { if(f[s | t[son].tag][son].len > f[s][cur].len + 1) { f[s | t[son].tag][son] = DP(f[s][cur].len + 1, s, cur); } if((s | t[son].tag) == dst) { stk[++top] = t[son].curchar; return f[s | t[son].tag][son]; } if(!vis[(s | t[son].tag)][son]) { q.push(make_pair(son, (s | t[son].tag))); vis[(s | t[son].tag)][son] = true; } } else { if(f[s][son].len > f[s][cur].len + 1) { f[s][son] = DP(f[s][cur].len + 1, s, cur); } if(!vis[s][son]) { q.push(make_pair(son, s)); vis[s][son] = true; } } } } } inline void write(DP res) { int st = res.preS, cur = res.preNo, tmp; while(cur) { stk[++top] = t[cur].curchar; tmp = st; st = f[st][cur].preS; cur = f[tmp][cur].preNo; } while(top) { putchar(stk[top--]); } putchar(' '); return; } int main() { scanf("%hd", &n); dst = (1 << n) - 1; for(short i = 1; i <= n; ++i) { scanf("%s", str); Insert(str, i); } getfail(); for(short i = (1 << 12) - 1; i >= 0; --i) { for(short j = 825 - 1; j >= 0; --j) { f[i][j].len = 32765; } } write(dp()); return 0; } /* 6 AA AAB AB A C AA */