J - 病毒侵襲持續中 HDU - 3065

 

小t非常感謝大家幫忙解決了他的上一個問題。然而病毒侵襲持續中。在小t的不懈努力下,他發現了網路中的“萬惡之源”。這是一個龐大的病毒網站,他有着好多好多的病毒,但是這個網站包含的病毒很奇怪,這些病毒的特徵碼很短,而且只包含“英文大寫字符”。當然小t好想好想爲民除害,但是小t從來不打沒有準備的戰爭。知己知彼,百戰不殆,小t首先要做的是知道這個病毒網站特徵:包含多少不同的病毒,每種病毒出現了多少次。大家能再幫幫他嗎?

Input

第一行,一個整數N(1<=N<=1000),表示病毒特徵碼的個數。 
接下來N行,每行表示一個病毒特徵碼,特徵碼字符串長度在1—50之間,並且只包含“英文大寫字符”。任意兩個病毒特徵碼,不會完全相同。 
在這之後一行,表示“萬惡之源”網站源碼,源碼字符串長度在2000000之內。字符串中字符都是ASCII碼可見字符(不包括回車)。 

Output

按以下格式每行一個,輸出每個病毒出現次數。未出現的病毒不需要輸出。 
病毒特徵碼: 出現次數 
冒號後有一個空格,按病毒特徵碼的輸入順序進行輸出。 

Sample Input

3
AA
BB
CC
ooxxCC%dAAAoen....END

Sample Output

AA: 2
CC: 1

        
  

Hint

Hit:
題目描述中沒有被提及的所有情況都應該進行考慮。比如兩個病毒特徵碼可能有相互包含或者有重疊的特徵碼段。
計數策略也可一定程度上從Sample中推測。

        
 AC自動機模板題

只有一個文本串進行匹配,題目要求記錄文本串中出現多少個病毒特徵碼(注意不是多少種),那麼在遍歷後綴時

不用做標記,直接遍歷到底即可。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<iostream>
using namespace std;
const int maxn=5e4+7;
const int branch=27;
queue<int> mmp;
int val[1010];//存放病毒特徵碼出現的次數
class AcTireNode
{
public:
    int next[branch];
    int id,flag;//0爲初始值  num記錄該病毒編號   flag記錄該節點被flag編號的文本遍歷了
    int fail;
    void clear()
    {
        fail=0;
        for(int i=0; i<branch; ++i)
            next[i]=-1;
        id=flag=0;
    }
};
class AcTire
{
private:
    AcTireNode *node;
    int top;
public:
    AcTire()
    {
        node=new AcTireNode[maxn];
        node[0].clear();
        top=0;
    }
    int hash_letter(char c)
    {
        if(c>='A'&&c<='Z')
         return c-'A';
        return 26;
    }
    void insert(char *s,int num)
    {
        int now=0;
        while(*s)
        {
            int i=hash_letter(*s);
            if(node[now].next[i]==-1)
            {
                node[now].next[i]=++top;
                node[top].clear();
            }
            now=node[now].next[i];
            ++s;
        }
        node[now].id=num;
    }
    void Bulid_fail()//作用實現:找到每個節點所代表字符串的最大匹配
    {
        int now,to;
        for(int i=0; i<branch; ++i)
        {
            if(node[0].next[i]!=-1)
                mmp.push(node[0].next[i]);
        }
        while(!mmp.empty())
        {
            now=mmp.front();
            mmp.pop();
            for(int i=0; i<branch; ++i)
            {
                if(node[now].next[i]!=-1)
                {
                    mmp.push(node[now].next[i]);
                    to=node[now].fail;
                    while(to>0&&node[to].next[i]==-1)
                        to=node[to].fail;
                    if(node[to].next[i]!=-1)
                        to=node[to].next[i];
                    node[node[now].next[i]].fail=to;
                }
            }
        }
    }
    void Find_tx(char *tx)//計算文本串中所有病毒特徵碼出現的次數
    {
        int now=0;
        int to;
        while(*tx)
        {
            int i=hash_letter(*tx);
            while(now>0&&node[now].next[i]==-1)
                now=node[now].fail;
            if(node[now].next[i]!=-1)//有匹配的後綴
            {
                now=node[now].next[i];
                to=now;//開始找所有後綴匹配
                while(to>0)//這個節點 曾經是否被這個字符串 遍歷過
                {
                    if(node[to].id)
                        val[node[to].id]++;
                    to=node[to].fail;
                }
            }
            ++tx;
        }
    }
    void init()
    {
        top=0;
        node[0].clear();
    }
    ~AcTire()
    {
        delete []node;
    }
};
char tx[2001000],str[1010][60];
int main()
{
    AcTire dch;
    int n;
    while(~scanf("%d",&n))
    {
        dch.init();
        for(int i=1; i<=n; ++i)
        {
            scanf("%s",str[i]);
            dch.insert(str[i],i);
        }
        dch.Bulid_fail();
        scanf("%s",tx);
        memset(val,0,sizeof(val));
        dch.Find_tx(tx);
        for(int i=1;i<=n;++i)
        {
            if(val[i])
                printf("%s: %d\n",str[i],val[i]);
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章