首页 > 代码库 > HDU3247 AC自动机+dp

HDU3247 AC自动机+dp

题意:给出n个资源,m个病毒,将资源串拼接成一个串,必须包含所有的资源串,可以重叠,但是不能包含病毒,问最小的长度为多少

题解:所有串建AC自动机。对以资源串结尾的结点跑bfs,求出到其他资源串结尾的最小距离。当前结点的fail结点不能入队列,因为当前结点读下一个字符可能会遇到禁止字符串,而fail结点读相同字符可能没有遇到禁止字符串...所以每次直接将nex的可行结点入队列。(fail结点不入队列,直接设为与当前结点距离为0应该也是可行的,然而WA了)很多时候我都开始质疑数据问题了...

如果当前字符串本身包含另一个资源串,那距离不应当是0吗?有一种解释是dp的时候经过 | 操作就可以了。

 

  1 #include <bits/stdc++.h>
  2 #include <cstdio>
  3 #include <iostream>
  4 #include <algorithm>
  5 #define ll long long
  6 #define lson l, m, rt<<1
  7 #define rson m+1, r, rt<<1|1
  8 #define st first
  9 #define nd second
 10 #define mp make_pair
 11 #define pii pair<int, int>
 12 #define gg puts("gg");
 13 #define local
 14 //#define out1
 15 using namespace std;
 16 const int N  = 6e4+10;
 17 const int inf = 0x3f3f3f3f;
 18 int id(char c){
 19     return c == 1;
 20 }
 21 struct Tire{
 22     int nex[N][2], fail[N],end[N];
 23     int root, L;
 24     int node[15], tot;
 25     int newnode(){
 26         nex[L][0] = nex[L][1] = -1;
 27         end[L] = 0;
 28         return L++;
 29     }
 30     void init(){
 31         L = tot = 0;
 32         root = newnode();
 33     }
 34     void insert(char* s, int tag){
 35         int now = root;
 36         for(int i = 0; s[i]; i++){
 37             int p = id(s[i]);
 38             if(nex[now][p] == -1)
 39                 nex[now][p] = newnode();
 40             now = nex[now][p];
 41         }
 42         if(tag >= 0)
 43             end[now] |= 1<<tag;
 44         else end[now] = -1;
 45     }
 46     void build(){
 47         queue<int> Q;
 48         fail[root] = root;
 49         for(int i = 0; i < 2; i++){
 50             int& u = nex[root][i];
 51             if(u == -1)
 52                 u = root;
 53             else{
 54                 fail[u] = root;
 55                 Q.push(u);
 56             }
 57         }
 58         while(!Q.empty()){
 59             int now = Q.front();
 60             Q.pop();
 61             for(int i = 0; i < 2; i++){
 62                 int& u = nex[now][i];
 63                 if(u == -1)
 64                     u = nex[ fail[now] ][i];
 65                 else{
 66                     fail[u] = nex[ fail[now] ][i];
 67                     end[u] |= end[ fail[u] ];
 68                     Q.push(u);
 69                 }
 70             }
 71         }
 72     }
 73 };
 74 Tire ac;
 75 char s[N];
 76 void gmin(int& a, int b){
 77     if(a > b) a = b;
 78 }
 79 int dis[N], ve[N], tot;
 80 int w[555][555];
 81 
 82 void bfs(int node, int i){
 83     memset(dis, 0x3f, sizeof(dis));
 84     queue<int> Q;
 85     Q.push(node); dis[node] = 0;
 86     int s = 0;
 87 
 88     #ifdef out1
 89     int j = node;
 90     while(ac.fail[j] != ac.root){
 91         j = ac.fail[j];
 92         dis[j] = 0;
 93     }
 94     dis[j] = 0;
 95     #endif
 96 
 97     while(!Q.empty()){
 98         int sz = Q.size();
 99         s++;
100         while(sz--){
101             int f = Q.front(); Q.pop();
102             for(int j = 0; j < 2; j++){
103                 int to = ac.nex[f][j];
104                 if(dis[to] < inf||ac.end[to] < 0) continue ;
105                 Q.push(to);
106                 dis[to] = s;
107 
108                 #ifdef out1
109                 while(ac.fail[to] != ac.root&&dis[ac.fail[to]] == inf){
110                     to = ac.fail[to];
111                     dis[to] = s;
112                 }
113                 #endif
114             }
115         }
116     }
117     for(int j = 0; j < tot; j++)
118         w[i][j] = dis[ ve[j] ];
119 }
120 int dp[555][1<<11];
121 int main(){
122     #ifdef locl
123     freopen("in", "r", stdin);
124     #ifdef out1
125         freopen("out1", "w", stdout);
126     #else
127         freopen("out2", "w", stdout);
128     #endif // out1
129     #endif // locl
130     int n, m, t, ca = 1;
131     while(~scanf("%d%d", &n, &m), n+m){
132         ac.init();
133 
134         memset(w, 0x3f, sizeof(w));
135         for(int i = 0; i < n; i++){
136             w[i][i] = 0;
137             scanf("%s", s);
138             ac.insert(s, i);
139         }
140         for(int i = 0; i < m; i++){
141             scanf("%s", s);
142             ac.insert(s, -1);
143         }
144         ac.build();
145 
146         tot = 0;
147         for(int i = 0; i < ac.L; i++)
148             if(!i||ac.end[i] > 0) ve[tot++] = i;
149         memset(w, 0x3f, sizeof(w));
150         for(int i = 0; i < tot; i++)
151             bfs(ve[i], i);
152 //        for(int i = 0; i < tot; i++){
153 //            for(int j = 0; j < tot; j++)
154 //                printf("%10d ", w[i][j]);
155 //            puts("");
156 //        }
157 
158         memset(dp, 0x3f, sizeof(dp));
159         for(int i = 0; i < tot; i++)
160             dp[i][ ac.end[ve[i]] ] = w[0][i];
161         for(int i = 0; i < (1<<n); i++){
162             for(int j = 0; j < tot; j++){
163                 if( dp[j][i] < 0x3f3f3f3f ) for(int k = 0; k < tot; k++)
164                     if(j != k&&w[j][k] < 0x3f3f3f3f)
165                         gmin(dp[k][i|ac.end[ve[k]]], dp[j][i]+w[j][k]);
166             }
167         }
168 
169 //        for(int i = 0; i < n; i++)
170 //            for(int j = 0; j < (1<<n); j++)
171 //                printf("%d %d: %d\n", i, j, dp[i][j]);
172 
173         int ans = inf;
174         for(int i = 0; i < tot; i++)
175             ans = min(ans, dp[i][ (1<<n)-1 ]);
176         printf("%d\n", ans);
177     }
178     return 0;
179 }
180 /*
181 2 2
182 1110
183 0111
184 101
185 1001
186 
187 3 3
188 0001000
189 00100
190 010
191 11
192 111
193 1111
194 */

 

HDU3247 AC自动机+dp