[BFS]luogu P2536 [AHOI2005]病毒检测
题面
https://www.luogu.com.cn/problem/P2536
分析
考虑建一个像trie的东西,即向下一个节点连代表字母的边
那么对于 AGCT 就直接向下一个节点连边
对于 ? 则可以向下一个节点连所有字母的边
对于 * ,我们采用对通配符的惯用操作,向自己连所有字母的边,即构造自环,表示匹配的时候可以是任意串
那么匹配的时候,在匹配串里正常移动,模式串里BFS,但是会T
考虑优化,发现对于匹配串的当前位置转移到下一个位置,在模式串中的每个点只能到达一次
所以用滚动队列跑BFS,每次扩展状态的时候标记一个 added 数组即可,记得清空
同时跑到匹配串和模式串的结尾则是一个未知病毒
代码
#include <iostream> #include <cstdio> #include <queue> #include <cstring> using namespace std; const int N=510; struct Graph { int v,w,nx; }g[8*N]; int cnt,list[2*N],gcnt; int n,m,ans; char s[2*N]; bool added[2*N]; void Add(int u,int v,int w) {g[++cnt]=(Graph){v,w,list[u]};list[u]=cnt;} void BFS() { queue<int> q[2];int e=0; while (!q[0].empty()) q[0].pop();while (!q[1].empty()) q[1].pop(); q[e].push(0); for (int j=1;j<m;j++) { memset(added,0,sizeof added); while (!q[e].empty()) { int u=q[e].front();q[e].pop(); for (int i=list[u];i;i=g[i].nx) if (g[i].w==s[j]&&!added[g[i].v]) added[g[i].v]=1,q[e^1].push(g[i].v); } e^=1; } while (!q[e].empty()) { int u=q[e].front();q[e].pop(); for (int i=list[u];i;i=g[i].nx) if (g[i].w==s[m]&&g[i].v==gcnt) return; } ans++; } int main() { scanf("%s",s+1);m=strlen(s+1); for (int i=1;i<=m;i++) { switch (s[i]) { case '?':{ Add(gcnt,gcnt+1,'A');Add(gcnt,gcnt+1,'G');Add(gcnt,gcnt+1,'C');Add(gcnt,gcnt+1,'T');gcnt++; break; } case '*':{ Add(gcnt,gcnt,'A');Add(gcnt,gcnt,'G');Add(gcnt,gcnt,'C');Add(gcnt,gcnt,'T'); break; } default:{ Add(gcnt,gcnt+1,s[i]);gcnt++; break; } } } scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%s",s+1),m=strlen(s+1),BFS(); printf("%d\n",ans); }
在日渐沉没的世界里,我发现了你。