BZOJ1195 : [HNOI2006]最短母串

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('\n');
    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
*/

 

posted @ 2018-07-20 21:01  EvalonXing  阅读(173)  评论(0编辑  收藏  举报