题意:给你N个串,M个危险串,求一个最短的串包含N个串但不包含任一个危险串,求最短串长度。
AC自动机+DP。。
预处理出所有合法节点,计算每个串和其他串的最短距离,也就是一个串最少要在后面加几个字母才能包含另外一个串而且不包含危险串。
然后就是经典的TSP问题了。状压DP即可。
2 2 1110 0111 101 1001 0 0
5
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define prt(k) cout<<#k"="<<k<<endl; inline void Max(int& a,int b) { if(a<b) a=b; } inline void Min(int& a,int b) { if(a>b) a=b; } const int N=61022; #define inf 0x3f3f3f3f const int Char=2; int ch[N][2],fail[N]; int endr[N]; ///resource bool endv[N]; ///virus int root,L; int newnode() { memset(ch[L],-1,sizeof ch[L]);endv[L]=0; endr[L]=0; return L++; } void init() { L=0; root=newnode(); } void insert(char s[],int id) { int n=strlen(s),u=root; for(int i=0;i<n;i++) { int& tmp=ch[u][s[i]-'0']; if(tmp==-1) tmp=newnode(); u=tmp; } if(id==-1) endv[u]=1; else endr[u]|=(1<<id); } void BUILD() { queue<int> q; for(int i=0;i<Char;i++) { int& tmp=ch[root][i]; if(tmp==-1) tmp=root; else { fail[tmp]=root; q.push(tmp); } } while(!q.empty()) { int u=q.front(); q.pop(); endr[u]|=endr[fail[u]]; endv[u]|=endv[fail[u]]; for(int i=0;i<Char;i++) { int& tmp=ch[u][i]; if(tmp==-1) tmp=ch[fail[u]][i]; else { fail[tmp]=ch[fail[u]][i]; q.push(tmp); } } } } char s[N]; int n,m; int pos[222],tot; int dis[N],d[211][211]; void spfa(int id) ///pos[id] { queue<int> q; memset(dis,-1,sizeof dis); dis[pos[id]]=0; q.push(pos[id]); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<2;i++) { int v=ch[u][i]; if(endv[v]==0&&dis[v]==-1) { dis[v]=dis[u]+1; q.push(v); } } } for(int i=0;i<tot;i++) d[id][i]=dis[pos[i]]; } int dp[1033][111]; int main() { while(scanf("%d%d",&n,&m)==2&&n) { init(); for(int i=0;i<n;i++) { scanf("%s",s);insert(s,i); } for(int i=0;i<m;i++) { scanf("%s",s);insert(s,-1); } BUILD(); tot=0; ///legal point pos[tot++]=root; for(int i=0;i<L;i++) if(!endv[i]&&endr[i]>0) pos[tot++]=i; for(int i=0;i<tot;i++) spfa(i); memset(dp,63,sizeof dp); dp[0][0]=0; for(int i=0;i<(1<<n);i++) for(int j=0;j<tot;j++) for(int k=0;k<tot;k++) { int t=i|endr[pos[k]]; Min(dp[t][k],dp[i][j]+d[j][k]); } int res=inf; for(int i=0;i<tot;i++) Min(res,dp[(1<<n)-1][i]); printf("%d\n",res+1); } }