【AC自动机】 HDOJ 3247 Resource Archiver

来源:互联网 发布:自动答题软件 编辑:程序博客网 时间:2024/06/05 20:57

AC自动机+状态压缩DP。。一种比较简单的做法是用找一个结构体,保存在AC自动机上走到那个点,当前的字符串长度和已经包含的字符串。然后把初始状态丢到队列里用BFS搜。。然后就没了,这样子做效率会低一点。。

#include <iostream>#include <sstream>#include <algorithm>#include <vector>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <climits>#define maxn 60000#define eps 1e-6#define mod 10007#define INF 99999999#define lowbit(x) ((x)&(-(x)))#define lson o<<1, L, mid#define rson o<<1 | 1, mid+1, Rtypedef long long LL;using namespace std;struct trie{int next[maxn][2];int fail[maxn];int end[maxn];char s[maxn];queue<int> q;int top, now, root;int newnode(void){end[top] = 0;fail[top] = -1;next[top][0] = next[top][1] = -1;return top++;}void init(void){top = 0;root = newnode();}void insert(int x){int len = strlen(s), i, k;now = root;for(i = 0; i < len; i++) {k = s[i] - '0';if(next[now][k] == -1)next[now][k] = newnode();now = next[now][k];}end[now] = x;}void build(void){now = root;for(int i = 0; i < 2; i++)if(next[now][i] == -1)next[now][i] = root;else {fail[next[now][i]] = root;q.push(next[now][i]);}while(!q.empty()) {now = q.front();q.pop();if(end[fail[now]] == -1) end[now] = -1;if(end[fail[now]] > 0) end[now] |= end[fail[now]];for(int i = 0; i < 2; i++)if(next[now][i] == -1)next[now][i] = next[fail[now]][i];else {fail[next[now][i]] = next[fail[now]][i];q.push(next[now][i]);}}}}tmp;struct node{int k, j;int step;}tmp1, now;queue<node> q;bool vis[1100][maxn];int n, m;void init(void){memset(vis, 0, sizeof vis);}void read(void){int temp = 1, i;tmp.init();for(i = 0; i < n; i++) {scanf("%s", tmp.s);tmp.insert(temp);temp<<=1;}for(i = 0; i < m; i++) {scanf("%s", tmp.s);tmp.insert(-1);}tmp.build();}void work(void){int i, ans = 0;for(i = 0; i < n; i++)ans<<=1, ans+=1;tmp1.k = 0, tmp1.j = 0, tmp1.step = 0;while(!q.empty()) q.pop();q.push(tmp1);while(!q.empty()) {now = q.front();q.pop();if(vis[now.k][now.j]) continue;vis[now.k][now.j] = 1;if(now.k == ans) {printf("%d\n", now.step);break;}for(i = 0; i < 2; i++) {if(tmp.end[tmp.next[now.j][i]] == -1)continue;else {tmp1.k = now.k | tmp.end[tmp.next[now.j][i]];tmp1.j = tmp.next[now.j][i];tmp1.step = now.step + 1;q.push(tmp1);}}}}int main(void){while(scanf("%d%d", &n, &m), n!=0 || m!=0) {init();read();work();}}


那种方法要遍历所有的状态,由于状态太多在ZOJ上会MLE。。有一种更好的办法。。先在AC自动机上作预处理,求出根节点和每一个串的末尾到其他串的末尾的最短距离。。然后dp[I][J]表示第i个状态最后一个串是j串的状态。。然后就可以开始状态转移了。。


#include <iostream>#include <sstream>#include <algorithm>#include <vector>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <climits>#define maxn 100005#define eps 1e-6#define mod 10007#define INF 99999999#define lowbit(x) ((x)&(-(x)))#define lson o<<1, L, mid#define rson o<<1 | 1, mid+1, Rtypedef long long LL;using namespace std;struct trie{int next[maxn][2];int fail[maxn];int end[maxn];char s[maxn];queue<int> q;int top, now, root;int newnode(void){end[top] = 0;fail[top] = -1;next[top][0] = next[top][1] = -1;return top++;}void init(void){top = 0;root = newnode();}void insert(int x){int len = strlen(s), i, k;now = root;for(i = 0; i < len; i++) {k = s[i] - '0';if(next[now][k] == -1)next[now][k] = newnode();now = next[now][k];}end[now] = x;}void build(void){now = root;for(int i = 0; i < 2; i++)if(next[now][i] == -1)next[now][i] = root;else {fail[next[now][i]] = root;q.push(next[now][i]);}while(!q.empty()) {now = q.front();q.pop();if(end[fail[now]] == -1) end[now] = -1;if(end[fail[now]] > 0) end[now] |= end[fail[now]];for(int i = 0; i < 2; i++)if(next[now][i] == -1)next[now][i] = next[fail[now]][i];else {fail[next[now][i]] = next[fail[now]][i];q.push(next[now][i]);}}}}tmp;int n, m, cnt;int pos[maxn];int dis[maxn];int g[20][20];bool vis[maxn];queue<int> q;int dp[1100][20];void init(void){cnt = 0;pos[cnt++] = 0;memset(g, 0, sizeof g);}void read(void){int i;tmp.init();for(i = 0; i < n; i++) {scanf("%s", tmp.s);tmp.insert(1<<i);pos[cnt++] = tmp.now;}for(i = 0; i < m; i++) {scanf("%s", tmp.s);tmp.insert(-1);}tmp.build();}void bfs(int x){int i, now = pos[x];memset(vis, 0, sizeof vis);for(i = 0; i < tmp.top; i++)dis[i] = INF;dis[now] = 0;q.push(now);vis[now] = true;while(!q.empty()) {now = q.front();q.pop();for(i = 0; i < 2; i++)if(tmp.end[tmp.next[now][i]] >= 0 &&  !vis[tmp.next[now][i]]) {vis[tmp.next[now][i]] = true;dis[tmp.next[now][i]] = min(dis[now] + 1, dis[tmp.next[now][i]]);q.push(tmp.next[now][i]);}}for(i = 0; i < cnt; i++)g[x][i] = dis[pos[i]];}void debug(void){int i, j;for(i = 0; i < cnt; i++) {for(j = 0; j < cnt; j++)printf("%d ", g[i][j]);printf("\n");}}void work(void){int i, j, k, ans;for(i = 0; i < cnt; i++)bfs(i);for(i = 0; i < (1<<n); i++)for(j = 0; j < cnt; j++)dp[i][j] = INF;dp[0][0] = 0;for(i = 0; i < (1<<n); i++)for(j = 0; j < cnt; j++)if(dp[i][j] != INF)for(k = 0; k < cnt; k++) {int t = tmp.end[pos[k]] | i;dp[t][k] = min(dp[t][k], dp[i][j] + g[j][k]);}ans = INF;for(i = 0; i < cnt; i++)ans = min(ans, dp[(1<<n)-1][i]);printf("%d\n", ans);}int main(void){while(scanf("%d%d", &n, &m), n!=0 || m!=0) {init();read();work();}return 0;}


0 0