2 2 1110 0111 101 1001 0 0
5
题意:给定n个子串,m个病毒串,然后让合并,使得串尽可能的短,但是不能含有病毒串,
这个题好难,n不超过10,看了别人的思路,先把子串与病毒串插进ac自动机去,子串标记为对应的状态,病毒串末尾标记为-1,然后把合法的子串节点取出来,然后通过bfs求两两之间的
最短路,然后状态压缩dp。
代码:
/* ***********************************************
Author :xianxingwuguan
Created Time :2014-2-5 17:31:21
File Name :4.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
struct node{
int next[60010][2],end[60010],fail[60030];
int root,L;
int newnode(){
next[L][0]=next[L][1]=-1;
end[L++]=0;
return L-1;
}
void init(){
L=0;
root=newnode();
}
void insert(char *str,int id){
int len=strlen(str);
int now=root;
for(int i=0;i<len;i++){
int p=str[i]-‘0‘;
if(next[now][p]==-1)
next[now][p]=newnode();
now=next[now][p];
}
if(id==-1)
end[now]=-1;
else end[now]|=(1<<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 dp[1<<10][60],dis[60][60],pnt[100],cnt,que[100010],dist[100000];
void bfs(int s){
for(int i=0;i<L;i++)
dist[i]=INF;
dist[pnt[s]]=0;
int front=0,rear=0;
que[rear++]=pnt[s];
while(front<rear){
int now=que[front++];
for(int i=0;i<2;i++){
int u=next[now][i];
if(end[u]==-1||dist[u]!=INF)
continue;
dist[u]=dist[now]+1;
que[rear++]=u;
}
}
for(int i=0;i<cnt;i++)dis[s][i]=dist[pnt[i]];
}
void F1(int n){
cnt=0;
for(int i=0;i<L;i++)
if(i==0||end[i]>0)
pnt[cnt++]=i;
// cout<<"haha:"<<L<<" "<<cnt<<endl;
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)continue;
for(int k=0;k<cnt;k++)
dp[i|end[pnt[k]]][k]=min(dp[i|end[pnt[k]]][k],dp[i][j]+dis[j][k]);
}
int ans=INF;
for(int i=0;i<cnt;i++)
ans=min(ans,dp[(1<<n)-1][i]);
cout<<ans<<endl;
}
}ac;
char str[10030];
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
int i,j,k,m,n;
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0)break;
ac.init();
for(i=0;i<n;i++){
scanf("%s",str);
ac.insert(str,i);
}
while(m--){
scanf("%s",str);
ac.insert(str,-1);
}
ac.build();
ac.F1(n);
}
return 0;
}
原文:http://blog.csdn.net/xianxingwuguan1/article/details/18941079