AC自动机+状压DP
首先对所有串建AC自动机,然后对于每个资源串,算出从串末走到其他资源串末所需的距离(中途避开非法点)
也就是算出两两间的距离。。。然后就变成旅行商问题了。
计算距离的时候要考虑一下。。直接从末尾走的话可能求出来的并不是最短路
所以要从fail和ch(就是虚边和实边)一起转移,走实边的话加进队列,虚边只能更新距离(不然可能非法)
但似乎正确性存疑?。。可能存在 三个资源串,分别按照最短距离拼在一起后会包含病毒串 的情况。。。
反正我的程序会炸,但网上一些标程没事= =。。。另外本题数据极弱,随机数据就能艹翻一大坨标程系列
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define next NEXT 5 using namespace std; 6 const int maxn=60023,inf=1002333333; 7 int ch[maxn][2],next[maxn][2],fail[maxn],tot; 8 bool gg[maxn],uu[maxn]; 9 int f1[maxn]; 10 char s[maxn],mp[11][1023];int len[11],ed[11]; 11 int d[11][11],dis[maxn],d1[maxn]; 12 int f[1026][11],two[11]; 13 int dl[maxn],l,r; 14 int i,j,k,n,m; 15 16 inline void getf1(int x){ 17 int i,p=0;f1[1]=0; 18 for(i=2;i<=len[x];i++){ 19 while(p&&mp[x][i]!=mp[x][p+1])p=f1[p]; 20 p+=mp[x][i]==mp[x][p+1],f1[i]=p; 21 } 22 } 23 inline bool check(int x,int y){ 24 int i,p=0; 25 for(i=1;i<=len[y];i++){ 26 while(p&&mp[y][i]!=mp[x][p+1])p=f1[p]; 27 p+=mp[y][i]==mp[x][p+1]; 28 if(p==len[x])return 1; 29 } 30 return 0; 31 } 32 33 inline void trie(int n,int id){ 34 int i,p=0; 35 for(i=1;i<=n;i++){ 36 s[i]-='0'; 37 if(!ch[p][s[i]])ch[p][s[i]]=++tot,p=tot; 38 else p=ch[p][s[i]]; 39 } 40 if(!id)gg[p]=1;else ed[id]=p;//printf(" gg:%d ",p); 41 } 42 inline void getfail(){ 43 int i,now,p,j;l=0,r=1,dl[1]=0; 44 while(l<r){ 45 now=dl[++l]; 46 for(i=0;i<2;/*printf("%d %d next:%d ",now,i,next[now][i]),*/i++)if(ch[now][i]){ 47 dl[++r]=j=next[now][i]=ch[now][i]; 48 for(p=fail[now];p&&!ch[p][i];p=fail[p]); 49 if(!now)fail[j]=0;else fail[j]=ch[p][i]; 50 gg[j]|=gg[fail[j]]; 51 }else{ 52 for(p=fail[now];p&&!ch[p][i];p=fail[p]); 53 next[now][i]=ch[p][i]; 54 } 55 } 56 for(i=0;i<=tot;i++)if(gg[i]) 57 for(j=0/*,printf("!! gg:%d ",i)*/;j<2;j++)if(ch[i][j])gg[ch[i][j]]=1; 58 } 59 inline void bfs(int s){ 60 memset(dis,255,(tot+1)<<2);memset(uu,0,tot+1); 61 int l=0,r=0,i,now,j; 62 if(!gg[s])dl[++r]=s,dis[s]=d1[s]=0,uu[s]=1; 63 for(i=fail[s];i;i=fail[i])if(!gg[i])dis[i]=0; 64 while(l<r){ 65 now=dl[++l]; 66 for(i=0;i<2;i++)if(!gg[next[now][i]]&&!uu[next[now][i]]){ 67 dl[++r]=next[now][i];uu[dl[r]]=1;d1[dl[r]]=d1[now]+1; 68 if(dis[dl[r]]==-1)dis[dl[r]]=d1[dl[r]]; 69 for(j=fail[dl[r]];j;j=fail[j])if(dis[j]==-1)dis[j]=dis[dl[r]]; 70 // if(s==16)printf("walk:%d->%d ",now,next[now][i]); 71 } 72 } 73 // if(s==16) 74 // for(i=0;i<=tot;i++)printf(" %d->%d %d ",s,i,dis[i]); 75 } 76 int main(){ 77 freopen("in.txt","r",stdin); 78 for(i=two[0]=1;i<=10;i++)two[i]=two[i-1]<<1; 79 for(scanf("%d%d",&n,&m);n&&m;scanf("%d%d",&n,&m)){ 80 memset(ch,0,(tot+1)<<3),memset(next,0,(tot+1)<<3),memset(fail,0,(tot+1)<<2), 81 memset(gg,0,tot+1),tot=0; 82 83 for(i=1;i<=n;i++) 84 scanf("%s",mp[i]+1),mp[i][0]='%',len[i]=strlen(mp[i])-1; 85 for(i=1;i<n;i++)for(j=i+1;j<=n;j++)if(len[i]>len[j]) 86 swap(len[i],len[j]),swap(mp[i],mp[j]); 87 88 for(i=1;i<n;i++){ 89 getf1(i); 90 for(j=i+1;j<=n;j++)if(check(i,j)){gg[i]=1;/*printf("%d in %d ",i,j);*/break;} 91 } 92 int n1=0; 93 for(i=1;i<=n;i++)if(!gg[i])n1++,memcpy(mp[n1],mp[i],len[i]+1),len[n1]=len[i];//,printf("%s ",mp[n1]); 94 memset(gg,0,n+1); 95 96 97 for(i=1;i<=n1;i++)memcpy(s,mp[i],len[i]+1),trie(len[i],i); 98 for(i=1;i<=m;i++)scanf("%s",s+1),s[0]='%',trie(strlen(s)-1,0); 99 getfail(); 100 101 for(i=1;i<=n1;puts(""),i++){ 102 bfs(ed[i]); 103 for(j=1;j<=n1;/*printf("%s-->%s %d ",mp[i]+1,mp[j]+1,d[i][j]),*/j++)if(dis[ed[j]]!=-1)d[i][j]=dis[ed[j]];else d[i][j]=inf; 104 } 105 106 int mx=1<<n1; 107 for(i=0;i<mx;i++)memset(f[i],50,(n1+1)<<2); 108 for(i=1;i<=n1;i++)f[two[i-1]][i]=len[i]; 109 for(i=1;i<mx;i++){ 110 for(j=1;j<=n1;j++)if(i&two[j-1]) 111 for(k=1;k<=n1;k++)if(k!=j&&(i&two[k-1])&&d[k][j]<inf) 112 f[i][j]=min(f[i][j],f[i^two[j-1]][k]+d[k][j]); 113 } 114 int ans=inf; 115 for(i=1;i<=n1;i++)ans=min(ans,f[mx-1][i]); 116 } 117 return 0; 118 }