[HDU2222]Keywords Search 做題筆記

題目來源:http://acm.hdu.edu.cn/showproblem.php?pid=2222
這題是比較裸的AC自動機,很容易想出AC做法但卻並不容易AC。。。
1、首先!這題有重複的單詞!!
2、千萬不要在for循環裏用strlen!!這題匹配串長度1000000,如果每次循環都要strlen,那計算開銷是相當大的。我不在裏面打strlen時間343ms,如果在裏面大strlen則直接TLE。
3、最好不要用memset

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
const int N=500003;
int T,n,ans=0;
int ch[N][26],fail[N],danger[N],cnt=1;//id[N]
bool vis[N];
queue<int> q;
char s[1000009];
void ins (char *s,int x) {
    int n=strlen(s),p=1,c;
    for (int i=0;i<n;i++) {
        c=s[i]-'a';
        if (!ch[p][c]) ch[p][c]=++cnt;
        p=ch[p][c];
    }
    danger[p]++;
}

void getfail () {
    while (!q.empty()) q.pop();
    int p=1,k;fail[1]=0;
    q.push(1);
    while (!q.empty()) {
        p=q.front(); q.pop();
        for (int i=0;i<26;i++) {
            if (!ch[p][i]) continue;
            k=fail[p];
            while (!ch[k][i]) k=fail[k];
            fail[ch[p][i]]=ch[k][i];
            q.push(ch[p][i]);
        }
    }   
}

void get (int p) {
    for (int i=p;i;i=fail[i])
        if (!vis[i]) {
            vis[i]=1; q.push(i);
            if (danger[i]) ans+=danger[i];
        }
        else break;//這裏不要接着向下搜
}

void solve () {
    scanf("%s",s);
    int p=1,c,len=strlen(s);//就是這裏strlen一定要在for外面計算
    while (!q.empty()) q.pop();
    for (int i=0;i<len;i++) {
        c=s[i]-'a';
        while (!ch[p][c]) p=fail[p];
        p=ch[p][c]; 
        get(p);
    }
    while (!q.empty()) {
        vis[q.front()]=0;
        q.pop();
    }
}

int main () {
    char s[100];
    scanf("%d",&T);
    while (T--) {
        ans=0;cnt=1;
        //memset(ch,0,sizeof(ch));
        //memset(fail,0,sizeof(fail));
        //memset(danger,0,sizeof(danger));
        //memset(id,0,sizeof(id));
        for (int i=0;i<26;i++) ch[0][i]=1;
        scanf("%d",&n);
        for (int i=1;i<=n;i++) {
            scanf("%s",s);
            ins(s,i);
        }
        getfail();
        solve();
        printf("%d\n",ans);
        for (int i=0;i<=cnt;i++) {
            for (int j=0;j<26;j++) ch[i][j]=0;
            fail[i]=0;
            danger[i]=0;
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章