[AHOI2005]病毒检测

题目描述

科学家们在Samuel星球上的探险仍在继续。非常幸运的,在Samuel星球的南极附近,探险机器人发现了一个巨大的冰湖!机器人在这个冰湖中搜集到了许多RNA片段运回了实验基地。

科学家们经过几个昼夜的研究,发现这些RNA片段中有许多是未知的病毒!

每个RNA片段都是由A、C、T、G组成的序列。科学家们也总结出了Samuel星球上的“病毒模版片段”。一个模版片段是由A、C、T、G的序列加上通配符 和 ? 来表示。其中 的意思是可以匹配上0个或任意多个字符,而 ? 的意思是匹配上任意一个字母。

如果一个RNA片段能够和“病毒模版片段”相匹配,那么这个RNA片段就是未知的病毒。

例如,假设“病毒模版片段”为A*G?C。RNA片段:AGTC,AGTGTC都是未知的病毒,而RNA片段AGTGC则不是病毒。

由于,机器人搜集的这些RNA片段中除去病毒的其他部分都具有非常高的研究价值。所以科学家们希望能够分辨出其中哪些RNA片段不是病毒,并将不是病毒的RNA片段运回宇宙空间站继续进行研究。

科学家将这项任务交给了小联。现在请你为小联编写程序统计哪些RNA片段不是病毒。

输入输出格式

输入格式:
第一行有一个字符串,由A、C、T、G、*、? 组成。表示“病毒模版片段”。“病毒模版片段”的长度不超过1000。第二行有一个整数N(0<N<500),表示机器人搜集到的RNA片段的数目。随后的N行,每一行有一个字符串,由A、C、T、G组成,表示一个RNA片段。每个RNA片段的长度不超过500。注意:“病毒模版片段”和RNA片段的长度都至少为1。

输出格式:

只有一行输出,为整数M,即不是病毒的RNA片段的数目。

输入输出样例

输入样例#1:

A*G?C
    3
AGTC
AGTGTC
AGTGC

输出样例#1: 复制

1

说明

输入中的RNA片段AGTGC不是病毒。


有好多方法啊.....dp,字典树啊

trie树

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
const int maxn=1000+233;
using namespace std;
char ch[maxn];
typedef pair<int,int> par;
int n;
int ans;
short moon[maxn];
int tr[maxn*maxn][10];
int no[maxn];
int cnt,fin[maxn*maxn];
inline short change(char c){
    if(c=='A')return 1;
    else if(c=='G')return 2;
    else if(c=='C')return 3;
    else if(c=='T')return 4;
    else if(c=='?')return 5;
    else return 6;
}
inline void add(){
    cin>>ch;
    int now=0;
    int len=strlen(ch);
    for(int i=0;i<len;i++)no[i]=change(ch[i]);
    for(int i=0;i<len;i++){
        if( tr[now][ no[i] ] )now=tr[now][ no[i] ];
        else cnt++,tr[now][no[i]]=cnt,now=cnt;
    }
    fin[now]++;
}
queue< pair<int,int> >q;
inline void getans(int P){
    q.push(make_pair(1,0));
    while(!q.empty()){
        par p=q.front();q.pop();
        int now=p.second;//second匹配到位置<fir原字符 
        int point=p.first;
        if(moon[point]==6){
        q.push(make_pair(point+1,now));
        for(int i=1;i<5;i++){
        if(tr[now][i]){
            q.push(make_pair(point,tr[now][i]));
            q.push(make_pair(point+1,tr[now][i]));
        	}
      	  }
    	}
        else if(moon[point]==5)
        for(int i=1;i<5;i++){
        if(tr[now][i])q.push(make_pair(point+1,tr[now][i]));
        }
        else if(moon[point]){
        if(tr[now][moon[point]])
        q.push(make_pair(point+1,tr[now][moon[point]]));
        }
        if(point==P+1)
        ans+=fin[now],fin[now]=0;
    }
    cout<<n-ans;
}
int main(){
    cin>>ch+1;
    int len=strlen(ch+1);
    for(int i=1;i<=len;i++)moon[i]=change(ch[i]);
    cin>>n;
    for(int i=1;i<=n;i++)add();
    getans(len);
    return 0;
}

DP

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
const int maxn=1000+233;
using namespace std;
char ch[maxn];
int c[maxn];
int dp[maxn][maxn];
char a[maxn];
int n;
int L;
int ans;
inline bool match(char x,char y){
    return (x==y)||(x=='?');
}
inline void add(){
    cin>>a+1;
    memset(c,0x3f,sizeof c);
    memset(dp,0,sizeof dp);
    int len=strlen(a+1);
    dp[0][0]=1;
    for(int i=1;i<=L;i++){
        if(ch[i]!='*')
            for(int j=1;j<=len;j++){
                if(match(ch[i],a[j]))
                    if(dp[i-1][j-1]||ch[i-1]=='*'&&c[i-1]<j)
                dp[i][j]=1;
            }
        else{
            if(i==1)dp[1][0]=1;
            for(int j=1;j<=len;j++){
                dp[i][j]=dp[i-1][j]|dp[i][j-1];
                if(dp[i][j])c[i]=min(c[i],j);
            }
        }
    }
    if(!dp[L][len])ans++;
}
int main(){
    cin>>ch+1;
    L=strlen(ch+1);
    cin>>n;
    for(;n;n--)add();
    cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/ck666/p/8232108.html