GMOJ 3569. 正则表达式
Input
Output
对于每一组数据,如果正则表达式r能表示字符串str,输出“Yes”,否则输出“No”。
Solution
考虑对于题目所给的正则表达式建一个自动机。
设当前在处理 S[l...r] ,last 指向 当前自动机要继续扩展的点(ed)。
1.串联
last 向新增的 st 连一条空边,然后将 last 设为 ed
2.单个字符a
新建st、ed节点,然后连一条权值为此字符的边。
3." ( "
找到与之对应的")",新建一对st、ed节点,对于括号中间的字符串dg处理
4.并联
将 last (当前的 ed)与 S[l...r]的 ed 连一条空边,然后将 last 重设为S[l...r]的 st
5. " + "
当前 last 指向的 ed 向对应 st 连一条空边
6. " * "
第一步与 + 操作相同,但要多连一条 st -> ed 的空边
7. 别忘了最后将连一条 last 到S[l...r]的 ed 的空边哦~
PS:每次操作完后如果要更新 last 不要忘记,对于每一个要处理的字符串S[l, r],它们的 last 是独立的;
对于部分操作(例如2、3操作),其实是伴随着串联操作的。
最后我们需要判断构造出来的自动机十分能构造出字符串 str,
设 f[i][j] 表示 str 匹配到第i位,自动机上匹配到 j是否可行,转移显然,注意空边可以直接转移过去
最后看 f[n][ed] 是否为1即可
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 100 #define M 1000 #define fo(i, x, y) for(int i = x; i <= y; i ++) #define Mes(a, x) memset(a, x, sizeof a) struct EDGE { int next, to; char c; } edge[M + 1]; struct Edge { int next, to; } g[M + 1]; int head[M + 1], h[M + 1], f[N + 1][M + 1], Next[M + 1], pre[M + 1]; char ch[N + 1]; int tot = 0, n, m; struct Arr { int st, ed; } last_d; int cnt_edge = 0; void Add(int u, int v, char c) { edge[ ++ cnt_edge ] = (EDGE) { head[u], v, c }, head[u] = cnt_edge; } int cnt_g = 0; void Add(int u, int v) { g[ ++ cnt_g ] = (Edge) { h[u], v }, h[u] = cnt_g; } Arr Insert(int l, int r) { if (l > r) return (Arr) { 0, 0 }; int st = ++ tot, ed = ++ tot; Next[ed] = st; if (l == r) { Add(st, ed, ch[l]); return (Arr) { st, ed }; } int last = st; fo(i, l, r) { if (ch[i] == '(') { int s = 1; fo(j, i + 1, r) { s += ch[j] == ')' ? -1 : (ch[j] == '(' ? 1 : 0); if (! s) { Arr d = Insert(i + 1, j - 1); if (! d.st) break; Add(last, d.st), pre[d.st] = last; last = d.ed; i = j; break; } } } else if (ch[i] == '|') { Add(last, ed); last = st; } else if (ch[i] == '*') { Add(last, Next[last]), Add(Next[last], last); } else if (ch[i] == '+') { Add(last, Next[last]); } else if (ch[i] == ')') continue; else { Arr d = Insert(i, i); Add(last, d.st), pre[d.st] = last; last = d.ed; } } Add(last, ed); return (Arr) { st, ed }; } bool Dfs(int t, int x) { if (t > m && x == last_d.ed) return 1; if (f[t][x]) return 0; f[t][x] = 1; if (t <= m) { for (int i = head[x]; i; i = edge[i].next) if (edge[i].c == ch[t] && Dfs(t + 1, edge[i].to)) return 1; } for (int i = h[x]; i; i = g[i].next) if (Dfs(t, g[i].to)) return 1; return 0; } int main() { while (~ scanf("%s\n", ch + 1)) { Mes(head, 0), Mes(h, 0), tot = 0; n = strlen(ch + 1); last_d = Insert(1, n); scanf("%s\n", ch + 1); m = strlen(ch + 1); Mes(f, 0); puts(Dfs(last_d.st, 1) ? "Yes" : "No"); } return 0; }