HDU 2896 病毒侵袭 AC自动机

来源:互联网 发布:2017年优化设计答案 编辑:程序博客网 时间:2024/06/14 02:43

思路:对每个字符串在Trie树上找一遍即可。

注意:理论应该有10w个节点,但是10w个MLE了,所以开8w也能过。

http://acm.hdu.edu.cn/showproblem.php?pid=2896

/*********************************************    Problem : HDU 2896    Author  : NMfloat    InkTime (c) NM . All Rights Reserved .********************************************/#include <map>#include <set>#include <queue>#include <stack>#include <cmath>#include <ctime>#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>#define rep(i,a,b)  for(int i = (a) ; i <= (b) ; i ++) //遍历#define rrep(i,a,b) for(int i = (b) ; i >= (a) ; i --) //反向遍历#define repS(it,p) for(auto it = p.begin() ; it != p.end() ; it ++) //遍历一个STL容器#define repE(p,u) for(Edge * p = G[u].first ; p ; p = p -> next) //遍历u所连接的点#define cls(a,x)   memset(a,x,sizeof(a))#define eps 1e-8using namespace std;const int MOD = 1e9+7;const int INF = 0x3f3f3f3f;typedef long long LL;typedef unsigned long long ULL;int T,n,m,k;int fx[] = {0,1,-1,0,0};int fy[] = {0,0,0,-1,1};const int MAXN = 80005;const int MAX_SIZE = 95;int tot ; char s[10005];int virus[4];//需要输出病毒的编号int recv[4];class AC_automation {private:       struct Node {        int next[MAX_SIZE]; //节点的儿子        int stat ; //有几个字符是以当前节点结尾的    }t[MAXN]; //Trie 树上的节点    int fail[MAXN]; //失配指针public:        void init() {        tot = 1; cls(t,0); cls(fail,0);    }    void reset_stat(int len) {        rep(i,1,len) t[recv[i]].stat = virus[i];     }    void insert(char * str,int idx) {        int len = strlen(str) - 1;        rep(i,0,len) str[i] -= ' ';//ascii 表可见字符,所以减掉一个空格        int pre = 0 , nxt = 0 ;        rep(i,0,len) {            nxt = t[pre].next[str[i]];            if(nxt == 0) {                t[pre].next[str[i]] = tot ;                nxt = tot ++;            }            pre = nxt;            //printf("%d -> ",nxt);        }        //puts("");        t[nxt].stat = idx; //给每个字符串编号    }    void get_fail() {        queue<int>q;        q.push(0);        while(!q.empty()) {            int u = q.front();            rep(i,0,MAX_SIZE-1) {                if(t[u].next[i]) {                    q.push(t[u].next[i]);                    int tmp = u;                    while(fail[tmp]) {                        if(t[fail[tmp]].next[i]) {                            fail[t[u].next[i]] = t[fail[tmp]].next[i]; break;                        }                        tmp = fail[tmp];                    }                     if(u != 0 && !fail[t[u].next[i]]) {//处理fail[tmp] = 0 时的情况                        if(t[0].next[i]) fail[t[u].next[i]] = t[0].next[i];                    }                }            }            q.pop();        }        //rep(i,1,tot-1) printf("%d %d %d\n",i,fail[i],t[i].stat);      }    int query(char * str) {        int idx = 0;        int len = strlen(str) - 1;        rep(i,0,len) str[i] -= ' ';        int now = 0;        rep(i,0,len) {            while(now && (!t[now].next[str[i]])) now = fail[now];            now = t[now].next[str[i]];            int tmp = now;            while(tmp) {                if(t[tmp].stat) {                    idx ++ ;                    virus[idx] = t[tmp].stat;                    recv[idx] = tmp;                    t[tmp].stat = 0;                }                               tmp = fail[tmp];            }        }        return idx;    }};AC_automation ac;void input() {    char str[205];    ac.init();    getchar();//读掉一个回车    rep(i,1,n) {        gets(str);        ac.insert(str,i);    }    ac.get_fail();}void solve() {    scanf("%d",&m);    getchar();    int web_site; //有病毒网站的数目    int cnt = 0;    rep(i,1,m) {        gets(s);        rep(i,1,3) virus[i] = 0;        int len = ac.query(s);        if(len > 0) {            if(len >= 2) if(virus[1] > virus[2]) {swap(virus[1],virus[2]);swap(recv[1],recv[2]);}            if(len >= 3) if(virus[2] > virus[3]) {swap(virus[3],virus[2]);swap(recv[3],recv[2]);}            if(len >= 3) if(virus[1] > virus[2]) {swap(virus[1],virus[2]);swap(recv[1],recv[2]);}            cnt ++;            printf("web %d:",i);            rep(i,1,len) printf(" %d",virus[i]);            puts("");        }         ac.reset_stat(len);    }    printf("total: %d\n",cnt);}int main(void) {    //freopen("a.in","r",stdin);    while(~scanf("%d",&n)) {        input();        solve();    }    return 0;}
0 0