AC自动机DP poj 3691

在1+学长的指点下,成功理解并完成了自己的第一个AC自动机

首先要做的就是鄙视一下我自己,如果您是在网上搜代码发现了本博也可以尽情的鄙视博主……

我写的时候就告诉自己一定要写的简短一些,很不幸,这个绝对是你你能搜到的最长~~~~的AC自动机DP

在1+学长的帮助一下,完成了这个DP。

注意一些概念:trie图上的每个节点代表自动机上的状态,而边代表的是字符,自动机的状态有明显的无后效性。节点的状态也就是我们在DP中需要应用,状态的设计dp[i][j]当向自动机输入了长度为i的字符串后在j(节点)状态的最小代价。dp[i][j] = min(dp[i][j], dp[i - 1][j] + code(str[i - 1]) != k);

我们可以这样直观的看待自动机DP,我们在自动机的某个状态j上输入一个字符,然后判断他4种转移方式转移方式时候合法,转移到那些状态。知道输入终止未知。找到终止使得最小代价的状态

首先这个自动机和一般的AC自动机的 的fail指针的构造方法是一样的,但是构造fail指针的时候,需要处理一个很重要的事情:

处理对于一个非法串是另一个串的字串的情况!

if(NXT(p, i)->c)
                            NXT(u, i)->c++;

就是这行代码,解释一下原因:如果当前串的的某个状态节点的fail指针只向了一个非法的状态那么该状态也一定不合法。

例如

2

AGCTT

GC

AGCTTA这样的数据。

然后就是算法的关键了,如果构造一个tranfer函数(数组的形式表现的)来产生合法的转移方式。

tr[i][j] 表示i状态,然后向j字符转移的

首先判断当天的状态时候合法,如果nxt[j] == NULL那么就找他的fail,如果有nxt[j]选取 ,否则知道 NULL为止;如果回到了root有root->nxt[j] != NULL;p = root->nxt[j];

否则p = root;

然后就是赤裸裸的转移了

就此自动机DP完成~

代码如下

AC自动机DP
   
     
1 #include < iostream >
2 #include < cstdio >
3 #include < cstring >
4 #include < algorithm >
5 using namespace std;
6 const int INF = 10000000 ;
7 int code( char ch)
8 {
9 if (ch == ' A ' ) return 0 ;
10 if (ch == ' G ' ) return 1 ;
11 if (ch == ' C ' ) return 2 ;
12 if (ch == ' T ' ) return 3 ;
13 }
14 class ACAutoMachine
15 {
16 #define NXT(u, i) (u)->nxt[i] /* */
17 #define CC(u, v) memset(u, v, sizeof(u)) /* */
18 public :
19 void initialize()
20 {
21 pp = pool;
22 root = newNode();
23 }
24 void insert( char * str)
25 {
26 node * now = root;
27 while ( * str)
28 {
29 int idx = code( * str);
30 if (NXT(now, idx) == NULL)
31 NXT(now, idx) = newNode();
32 now = NXT(now, idx);
33 str ++ ;
34 }
35 now -> c ++ ;
36 }
37 void build ()
38 {
39 head = tail = 0 ;
40 q[tail ++ ] = root;
41 while (head != tail)
42 {
43 node * u = q[head ++ ], * p = NULL;
44 for ( int i = 0 ;i < KIND;i ++ )
45 {
46 if (NXT(u, i) == NULL)
47 continue ;
48 if (u == root)
49 NXT(u, i) -> fail = root;
50 else
51 {
52 p = u -> fail;
53 while (p)
54 {
55 if (NXT(p, i) == NULL)
56 {
57 p = p -> fail;
58 continue ;
59 }
60 NXT(u, i) -> fail = NXT(p, i);
61 // pass the c mark it as a dangrous node because the fail of is dangrous
62 // 一般自动机构造fail没有这句话
63 if (NXT(p, i) -> c)
64 NXT(u, i) -> c ++ ;
65 break ;
66 }
67 if (p == NULL)
68 NXT(u, i) -> fail = root;
69 }
70 q[tail ++ ] = NXT(u, i);
71 }
72 }
73 }
74 int DP ( int n, char * str)
75 {
76 int m = pp - pool;
77 make_tr(m);
78 for ( int i = 0 ;i <= n;i ++ )
79 fill(dp[i], dp[i] + m, INF);
80 dp[ 0 ][ 0 ] = 0 ;
81 for ( int i = 0 ;i < n;i ++ )
82 {
83 for ( int j = 0 ;j < m;j ++ )
84 {
85 if (dp[i][j] == INF || pool[j].c)
86 continue ;
87 for ( int k = 0 ;k < KIND;k ++ )
88 {
89 if (tr[j][k] != - 1 )
90 dp[i + 1 ][tr[j][k]] = min(dp[i + 1 ][tr[j][k]], dp[i][j] + (code(str[i]) != k));
91 }
92 }
93 }
94 int ans = INF;
95 for ( int i = 0 ;i < m;i ++ )
96 ans = min(ans, dp[n][i]);
97 if (ans == INF) return - 1 ;
98 else return ans;
99 }
100 private :
101 const static int KIND = 4 , MAXNODE = 1001 , N = 1001 ;
102 int dp[N][MAXNODE], tr[MAXNODE][KIND];
103 struct node
104 {
105 node * fail, * nxt[KIND];
106 int c;
107 }pool[MAXNODE], * pp, * root, * q[MAXNODE];
108 int head, tail;
109 node * newNode()
110 {
111 pp -> fail = NULL;
112 pp -> c = 0 ;
113 CC(pp -> nxt, 0 );
114 return pp ++ ;
115 }
116 void make_tr( int m)
117 {
118 memset(tr, - 1 , sizeof (tr));
119 for ( int i = 0 ;i < m;i ++ )
120 {
121 if (pool[i].c)
122 continue ;
123 for ( int j = 0 ;j < KIND;j ++ )
124 {
125 node * p = pool + i;
126 while (p)
127 {
128 if (p -> nxt[j] != NULL)
129 {
130 p = p -> nxt[j];
131 break ;
132 }
133 p = p -> fail;
134 }
135 if (p == NULL)
136 {
137 p = root;
138 if (p -> nxt[j] != NULL)
139 p = p -> nxt[j];
140 }
141 if (p -> c == 0 )
142 tr[i][j] = p - pool;
143 }
144 }
145 }
146 }AC;
147
148 char str[ 1001 ];
149 int main()
150 {
151 int n, cases = 1 ;
152 while (scanf( " %d " , & n) == 1 && n)
153 {
154 AC.initialize();
155 for ( int i = 0 ;i < n;i ++ )
156 {
157 scanf( " %s " , str);
158 AC.insert(str);
159 }
160 scanf( " %s " , str);
161 AC.build();
162 printf( " Case %d: %d\n " , cases ++ , AC.DP(strlen(str), str));
163 }
164 return 0 ;
165 }

你可能感兴趣的:(AC自动机)