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;
}
View Code

 

posted @ 2020-08-15 21:59  buzzhou  阅读(196)  评论(0编辑  收藏  举报