2 2 1110 0111 101 1001 0 0
5
把上面N个串拼起来,可重叠,不能包含下面的M个病毒串,拼出的串长度最小是多少。
构造AC自动机,标记病毒节点和非病毒节点包含的串。由于N只有10,dp的时候只要在单词的尾节点之间进行就行了,把所有单词的尾节点存下来,BFS预处理出这些节点之间的最短路,dp[i][j]表示第i个单词尾节点已经包含的串状态为j的最小长度,进行状态转移。
#include<cstdio> #include<cstring> #include<algorithm> #include<string> #include<iostream> #include<queue> using namespace std; const int MAXN=1010; const int MAXM=15; const int MAXL=100010; const int MAXNODE=60010; const int LOGMAXN=50; const int INF=0x3f3f3f3f; const int SIGMA_SIZE=2; const int MOD=20090717; int N,M,K; int p[MAXNODE],dis[MAXM][MAXM],d[MAXNODE]; int dp[MAXM][(1<<11)+10]; struct AC{ int ch[MAXNODE][SIGMA_SIZE]; int val[MAXNODE]; int f[MAXNODE]; int virus[MAXNODE]; int sz; void clear(){ memset(ch[0],0,sizeof(ch[0])); val[0]=0; virus[0]=0; sz=1; } int idx(char c){ return c-'0'; } int insert(char* s,int v){ int u=0; for(int i=0;s[i];i++){ int c=idx(s[i]); if(!ch[u][c]){ memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; virus[sz]=0; ch[u][c]=sz++; } u=ch[u][c]; } if(v>0) val[u]|=v; else virus[u]=1; } void get_fail(){ queue<int> q; f[0]=0; for(int c=0;c<SIGMA_SIZE;c++){ int u=ch[0][c]; if(u){ f[u]=0; q.push(u); } } while(!q.empty()){ int r=q.front(); q.pop(); for(int c=0;c<SIGMA_SIZE;c++){ int u=ch[r][c]; if(!u){ ch[r][c]=ch[f[r]][c]; continue; } q.push(u); f[u]=ch[f[r]][c]; val[u]|=val[f[u]]; virus[u]|=virus[f[u]]; } } } }ac; void get_dis(){ p[0]=0; K=1; memset(dis,-1,sizeof(dis)); for(int u=0;u<ac.sz;u++) if(!ac.virus[u]&&ac.val[u]){ p[K++]=u; } queue<int> q; for(int i=0;i<K;i++){ memset(d,-1,sizeof(d)); d[p[i]]=0; q.push(p[i]); while(!q.empty()){ int u=q.front(); q.pop(); for(int c=0;c<SIGMA_SIZE;c++){ int v=ac.ch[u][c]; if(!ac.virus[v]&&d[v]<0){ d[v]=d[u]+1; q.push(v); } } } for(int j=0;j<K;j++) dis[i][j]=d[p[j]]; } } void DP(){ memset(dp,INF,sizeof(dp)); dp[0][0]=0; int MAXSTATE=(1<<N)-1; for(int s=0;s<=MAXSTATE;s++) for(int i=0;i<K;i++) if(dp[i][s]!=INF){ for(int j=0;j<K;j++) if(dis[i][j]!=-1){ dp[j][s|ac.val[p[j]]]=min(dp[j][s|ac.val[p[j]]],dp[i][s]+dis[i][j]); } } int ans=INF; for(int i=0;i<K;i++) if(dp[i][MAXSTATE]!=INF){ ans=min(ans,dp[i][MAXSTATE]); } printf("%d\n",ans); } char str[MAXN]; int main(){ freopen("in.txt","r",stdin); while(scanf("%d%d",&N,&M)!=EOF&&(N||M)){ ac.clear(); for(int i=0;i<N;i++){ scanf("%s",str); ac.insert(str,1<<i); } for(int i=0;i<M;i++){ scanf("%s",str); ac.insert(str,-1); } ac.get_fail(); get_dis(); DP(); } return 0; }