P2536 [AHOI2005]病毒检测

题意:给出一个病毒串;给出n个询问串,问这些串是病毒串否?

    要我们找出不是病毒的串

思路:我们将询问串建字典树,然后来dfs跑这个病毒串  (bfs也可以)

     那么如何跑呢?

      假如病毒串当前位置是A T G C ,就判断是否能在字典树上继续往下走,不可以就直接返回

      假如是问号,那么就有4种可能,我们也枚举一下,然后往下跑即可

      假如是*号,我们就有多种可能  第一种是直接忽略,跑病毒串的下一个字符

                    第二种是像问号一样,枚举四种字符,然后跑下一个字符

                    第三种也是枚举4种字符,但不是跑一下字符,而是继续在这个字符停留(因为*可以表示无数个字符)

      然后凡是能跑完病毒串的,就是病毒(不满足病毒串的率先return了)

        那么跑完的判定条件是什么呢?  

          自然是跑到病毒串长度+1的位置拉

            然后最后再用总数减去这些病毒RNA数量,就是最后答案了

但是!这道题卡内存,我们用来标记的vis数组,得用bitset来表示才不会MLE

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=250010;
 4 int trie[maxn][6],num[maxn];
 5 int tot,ans=0,n,m,L;
 6 bitset<1001>vis[maxn];//请用bitset 不然会被卡空间
 7 char s[1005],str[505];
 8 int ark(char c)//将字符处理为各个数字
 9 {
10     if(c=='A') return 0;
11     if(c=='G') return 1;
12     if(c=='T') return 2;
13     if(c=='C') return 3;
14     if(c=='?') return 4;
15     return 5;
16 }
17 void make_trie(char sa[505])//建trie树 
18 {
19     int now=0,len=strlen(sa);
20     for(int i=0;i<len;i++){
21         int next=ark(sa[i]);
22         if(!trie[now][next]){
23             trie[now][next]=++tot;
24         }
25         now=trie[now][next];
26     }
27     num[now]++;//因为可能有重复字符串,所以这里是++,而不是赋为1
28 }
29 void dfs(int x,int now)
30 {
31     if(x==L)//如果匹配成功(一定为模式串结尾 ) 
32     {
33         ans+=num[now];
34         num[now]=0;//记得清0 不然就重复算了 
35         return;
36     }
37     if(vis[now][x])//记搜 
38     {
39         return; 
40     }
41     vis[now][x]=1;//赋初值 
42     if(ark(s[x])==4)//如果当前字符为? 
43     {
44         for(int i=0;i<=3;i++){
45             if(trie[now][i]){
46                 dfs(x+1,trie[now][i]);//将?当成任意一个字符匹配 
47             }
48         }
49     }
50     if(ark(s[x])==5)//如果当前字符为* 
51     {
52         dfs(x+1,now);//不匹配* 
53         for(int i=0;i<=3;i++)
54         {
55             if(trie[now][i])
56             {
57                 dfs(x+1,trie[now][i]);
58                 dfs(x,trie[now][i]);
59             }
60         }
61     }
62     if(trie[now][ark(s[x])])//如果当前字符为字母 
63     {
64         dfs(x+1,trie[now][ark(s[x])]);
65     }
66 }
67 int main()
68 {
69     scanf("%s",s);
70     L=strlen(s)+1;   //将病毒串长度+1,跑到这个位置就表明有该种类型的病毒
71     scanf("%d",&n);
72     for(int i=1;i<=n;i++){
73         scanf("%s",str);
74         make_trie(str);
75     }
76     dfs(0,0); //爆搜 
77     cout<<n-ans;//由于我们找的是病毒段,而题目求得是不是病毒段的串,就用 n-ans 
78     return 0;
79 }
View Code

借鉴自:https://www.cnblogs.com/dreagonm/p/10457141.html

posted @ 2020-04-07 21:24  古比  阅读(192)  评论(0编辑  收藏  举报