题目链接:Resource Archiver
解析:n个正常的串,m个病毒串,问包含所有正常串(可重叠)且不包含任何病毒串的字符串的最小长度为多少。
AC自动机 + bfs + 状态压缩DP
用最短路预处理出状态的转移。可以优化很多
AC代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
struct Trie{
int next[60010][2], fail[60010], end[60010];
int root, L;
int newnode(){
for(int i=0; i<2; i++) next[L][i] = -1;
end[L++] = 0;
return L-1;
}
void init(){
L = 0;
root = newnode();
}
void insert(char buf[], int id){
int len = strlen(buf);
int now = root;
for(int i=0; i<len; i++){
if(next[now][buf[i] - '0'] == -1)
next[now][buf[i] - '0'] = newnode();
now = next[now][buf[i] - '0'];
}
end[now] = id;
}
void build(){
queue<int> Q;
fail[root] = root;
for(int i=0; i<2; i++)
if(next[root][i] == -1) next[root][i] = root;
else{
fail[ next[root][i] ] = root;
Q.push(next[root][i]);
}
while(!Q.empty()){
int now = Q.front();
Q.pop();
if(end[ fail[now] ] == -1) end[now] = -1;
else 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]);
}
}
}
int g[11][11];
int dp[1025][11];
int cnt;
int pos[11];
int dis[60010];
void bfs(int k){
queue<int> q;
memset(dis, -1, sizeof(dis));
dis[pos[k]] = 0;
q.push(pos[k]);
while(!q.empty()){
int now = q.front();
q.pop();
for(int i=0; i<2; i++){
int tmp = next[now][i];
if(dis[tmp] < 0 && end[tmp] >= 0){
dis[tmp] = dis[now] + 1;
q.push(tmp);
}
}
}
for(int i=0; i<cnt; i++) g[k][i] = dis[pos[i]];
}
int solve(int n){
pos[0] = 0;
cnt = 1;
for(int i=0; i<L; i++)
if(end[i] > 0) pos[cnt++] = i;
for(int i=0; i<cnt; i++) bfs(i);
for(int i=0; i<(1<<n); i++)
for(int j=0; j<cnt; j++)
dp[i][j] = INF;
dp[0][0] = 0;
for(int i=0; i<(1<<n); i++)
for(int j=0; j<cnt; j++)
if(dp[i][j] < INF){
for(int k=0; k<cnt; k++){
if(g[j][k] < 0) continue;
if(j == k) continue;
dp[i | end[pos[k]]][k] = min(dp[i | end[pos[k]]][k], dp[i][j] + g[j][k]);
}
}
int ans = INF;
for(int i=0; i<cnt; i++)
ans = min(ans, dp[(1<<n)-1][i]);
return ans;
}
};
char buf[1010];
Trie ac;
int main(){
#ifdef sxk
freopen("in.txt", "r", stdin);
#endif // sxk
int n, m;
while(scanf("%d%d", &n, &m) == 2){
if(n == 0 && m == 0) break;
ac.init();
for(int i=0; i<n; i++){
scanf("%s", buf);
ac.insert(buf, 1<<i);
}
for(int i=0; i<m; i++){
scanf("%s", buf);
ac.insert(buf, -1);
}
ac.build();
printf("%d\n", ac.solve(n));
}
return 0;
}