[关闭]
@lychee123 2017-07-12T19:04:27.000000Z 字数 1489 阅读 1414

HDU 2222:Keywords Search(AC自动机判断长串中出现了多少个已知单词)

数据结构


题面链接

有t组测试数据,对于每组测试数据
给出N个单词(N <= 10000),每个单词都只包含小写字母(每个单词的长度不超过50)
接下来给你一个长串s(长度不超过1000000)
问上面的n个单词有多少个在长串s中出现过。

Sample Input
1
5
she
he
say
shr
her
yasherhs

Sample Output
3

AC自动机的模板题。但是有地方需要注意。
我们AC自动机的模板里面对于单词的标记是出现了就标记为1,这里由于可能出现相同的单词所以会重复去算。所以我们对于isword数组的存值为++。而不是==1.(在代码第21行)同时对于模板的find函数。66行到77行。我们应该标记已经出现的单词,ans加了之后就应该改变isword的值为0,不重复计数。

  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<algorithm>
  4. #include<queue>
  5. using namespace std;
  6. const int maxn=5e5+5;
  7. int last[maxn],f[maxn];
  8. int ch[maxn][26];
  9. int cnt=0;
  10. int isword[maxn];
  11. void insert(char s[])
  12. {
  13. int root=0;
  14. int l=strlen(s);
  15. for(int i=0;i<l;i++)
  16. {
  17. if(ch[root][s[i]-'a']==0)
  18. ch[root][s[i]-'a']=++cnt;
  19. root=ch[root][s[i]-'a'];
  20. }
  21. isword[root]++;
  22. }
  23. void getfail()
  24. {
  25. queue<int>q;
  26. f[0]=0;
  27. for(int i=0;i<26;i++)
  28. {
  29. int u=ch[0][i];
  30. if(u!=0)
  31. {
  32. f[u]=0;
  33. q.push(u);
  34. last[u]=0;
  35. }
  36. }
  37. while(!q.empty())
  38. {
  39. int r=q.front();
  40. q.pop();
  41. for(int c=0;c<26;c++)
  42. {
  43. int u=ch[r][c];
  44. if(u==0)
  45. {
  46. ch[r][c]=ch[f[r]][c];
  47. continue;
  48. }
  49. q.push(u);
  50. int v=f[r];
  51. while(v&&!ch[v][c])
  52. v=f[v];
  53. f[u]=ch[v][c];
  54. last[u]=isword[f[u]]?f[u]:last[f[u]];
  55. }
  56. }
  57. }
  58. int find(char T[])
  59. {
  60. int ans=0;
  61. int n=strlen(T);
  62. int j=0;
  63. for(int i=0;i<n;i++)
  64. {
  65. j=ch[j][T[i]-'a'];
  66. if(isword[j])
  67. {
  68. ans+=isword[j];
  69. isword[j]=0;
  70. }
  71. int temp=last[j];
  72. while(temp)
  73. {
  74. ans+=isword[temp];
  75. isword[temp]=0;
  76. temp=last[temp];
  77. }
  78. }
  79. return ans;
  80. }
  81. char s[maxn*2];
  82. char s1[10010];
  83. int main()
  84. {
  85. int t;
  86. scanf("%d",&t);
  87. while(t--)
  88. {
  89. memset(ch,0,sizeof(ch));
  90. memset(isword,0,sizeof(isword));
  91. int n;
  92. scanf("%d",&n);
  93. while(n--)
  94. {
  95. scanf("%s",s1);
  96. insert(s1);
  97. }
  98. getfail();
  99. scanf("%s",s);
  100. printf("%d\n",find(s));
  101. }
  102. return 0;
  103. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注