题目链接:hdu_3247_Resource Archiver
题意:
有n个资源串,m个病毒串,现在要将所有的资源串整合到一个串内,并且这个串不能包括病毒串,问最短的串长为多少
题解:
将资源串和病毒串都插入到AC自动机中,分别做好标记,然后用bfs求出0节点和所有资源串互相的最短距离,最后就是一个TSP的状态压缩DP。
#include<bits/stdc++.h>
#define F(i,a,b) for(int i=a;i<=b;i++)
using namespace std; const int AC_N=1e5+,tyn=;
struct AC_automation{
int tr[AC_N][tyn],so[AC_N],v[AC_N],Q[AC_N],fail[AC_N],tot;
inline int getid(char x){return x-'';}
void nw(){so[++tot]=,fail[tot]=,v[tot]=;memset(tr[tot],,sizeof(tr[tot]));}
void init(){tot=-,fail[]=-,nw();}
void insert(char *s,int idx,int fg,int x=){
for(int len=strlen(s),i=,w;i<len;x=tr[x][w],i++)
if(!tr[x][w=getid(s[i])])nw(),tr[x][w]=tot;
if(fg)so[x]=<<idx;else v[x]=;
}
void build(int head=,int tail=){
for(int i=;i<tyn;i++)if(tr[][i])Q[++tail]=tr[][i];
while(head<=tail)for(int x=Q[head++],i=;i<tyn;i++)
if(tr[x][i])fail[tr[x][i]]=tr[fail[x]][i],Q[++tail]=tr[x][i],
so[tr[x][i]]|=so[tr[fail[x]][i]],v[tr[x][i]]+=v[tr[fail[x]][i]];
else tr[x][i]=tr[fail[x]][i];
} }AC; char s[AC_N];
int path[][],pos[],dp[<<][],cnt,Q[AC_N],dis[AC_N],n,m; inline void up(int &a,int b){if(a>b)a=b;} void bfs(int u,int head=,int tail=)
{
memset(dis,-,sizeof(dis));
Q[++tail]=pos[u],dis[pos[u]]=;
while(head<=tail)
{
int now=Q[head++];
F(i,,)
{
int q=AC.tr[now][i];
if(dis[q]<&&!AC.v[now])dis[q]=dis[now]+,Q[++tail]=q;
}
}
F(i,,cnt)path[u][i]=dis[pos[i]];
} void fuck()//TSP的dp
{
memset(dp,-,sizeof(dp)),dp[][]=;
for(int i=;i<(<<n);i++)F(j,,cnt)if(dp[i][j]>=)F(k,,cnt)if(path[j][k]>=)
if(dp[i|AC.so[pos[k]]][k]==-)dp[i|AC.so[pos[k]]][k]=dp[i][j]+path[j][k];
else up(dp[i|AC.so[pos[k]]][k],dp[i][j]+path[j][k]);
int ans=INT_MAX;
F(i,,cnt)if(dp[(<<n)-][i]!=-)up(ans,dp[(<<n)-][i]);
printf("%d\n",ans==INT_MAX?-:ans);
} int main()
{
while(~scanf("%d%d",&n,&m)&&n+m)
{
AC.init(),cnt=;
F(i,,n-)scanf("%s",s),AC.insert(s,i,);
F(i,,m-)scanf("%s",s),AC.insert(s,i,);
AC.build();
F(i,,AC.tot)if(AC.so[i])pos[++cnt]=i;
F(i,,cnt)bfs(i);//求出0到所以资源串的距离和资源串到资源串之间的距离
fuck();
}
return ;
}