题意:
给出n个资源串,m个病毒串,现在要如何连接资源串使得不含病毒串(可以重叠)。
题解:
真心不会做。
这题注意点好多,稍不留意就wa。
看了题解我是这样理解的,我么可以把资源串和病毒串都放到ac机上,这样的做是为了把病毒串挑掉。在建ac机时,通过判断fail指针对应节点是否是病毒串,然后将fail指针的内容根性到这个节点。同理对于资源串也用相同方法。我们这样设置标记,病毒串ID=-1,资源串ID=对应状态(比如编号是i那么ID=1<<i)。后面建ac机可以整合这些状态。接着还要BFS得到剔除病毒串后可以用资源串到各个资源串的距离,这个方法很巧秒。之后就可以状压了dp[s][i]状态为s,ac机上节点i对应的最小长度。i不一定要在s中,因为可以通过多个部分整合成一个部分。其实建ac机时就将包含关系的资源串整合成了一个串,操作很巧妙的。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> using namespace std; #define B(x) (1<<(x)) typedef long long ll; const int oo=0x3f3f3f3f; const ll OO=1LL<<61; const ll MOD=20090717; const int maxn=1005; const int SIZE=60005; const int alph=2; char str[maxn]; int dp[B(10)+5][11]; int pos[11]; int dis[SIZE]; int maze[11][11]; struct AC { int next[SIZE][alph],fail[SIZE],ID[SIZE]; int root,cnt; void Init() { cnt=0; root=newNode(); } int newNode() { for(int i=0;i<alph;i++) next[cnt][i]=-1; ID[cnt++]=0; return cnt-1; } void Insert(char buff[],int id) { int now=root; int len=strlen(buff); for(int i=0,k;i<len;i++) { k=buff[i]-'0'; if(next[now][k]==-1) next[now][k]=newNode(); now=next[now][k]; } ID[now]=id; } void build() { queue<int>Q; fail[root]=root; int now=root; for(int i=0;i<alph;i++) { if(next[now][i]==-1) next[now][i]=root; else { fail[next[now][i]]=root; Q.push(next[now][i]); } } while(!Q.empty()) { now=Q.front(); Q.pop(); if(ID[fail[now]]==-1) ID[now]=-1;///和病毒串一样因此要改成-1,这样就相当于删除了病毒串 else ID[now]|=ID[fail[now]]; for(int i=0;i<alph;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]); } } } } void cmin(int& a,int b) { if(a==-1) a=b; else if(b<a) a=b; } void bfs(int s,int n) { queue<int>Q; memset(dis,-1,sizeof dis); dis[pos[s]]=0; Q.push(pos[s]); while(!Q.empty()) { int u=Q.front(); Q.pop(); for(int i=0;i<2;i++) { int v=next[u][i]; if(dis[v]==-1&&ID[v]!=-1)///因此只要处理到邻接的点即可,并不是多个点的路径 { dis[v]=dis[u]+1; Q.push(v); } } } for(int i=0;i<n;i++) maze[s][i]=dis[pos[i]]; } int DP(int n) { int nCnt; memset(maze,-1,sizeof maze); pos[0]=0; nCnt=1; for(int i=0;i<cnt;i++) if(ID[i]>0) pos[nCnt++]=i; for(int i=0;i<nCnt;i++) bfs(i,nCnt); memset(dp,0x3f,sizeof dp); dp[0][0]=0; int full=B(n)-1; for(int s=0;s<=full;s++) { for(int i=0;i<nCnt;i++) if(dp[s][i]!=oo) { //if(!(s&B(i)))continue; for(int j=0;j<nCnt;j++) if(maze[i][j]!=-1&&i!=j) { int st=s|ID[pos[j]]; cmin(dp[st][j],dp[s][i]+maze[i][j]); } } } int ans=oo; for(int i=0;i<nCnt;i++) cmin(ans,dp[full][i]); return ans; } }; AC ac; int main() { int n,m; while(scanf("%d %d",&n,&m)!=EOF) { if(n==0&&m==0)break; ac.Init(); for(int i=0;i<n;i++) { scanf("%s",str); ac.Insert(str,B(i)); } for(int i=0;i<m;i++) { scanf("%s",str); ac.Insert(str,-1); } ac.build(); cout<<ac.DP(n)<<endl; } return 0; } /** 5 2 01000111000001110001 11100000111000110011 00011100011001111011 10001100111101100010 10011110110001001111 10001110000011100011 11000110011110110001 ans=66 */