zoukankan      html  css  js  c++  java
  • 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
    ", ch + 1)) {
            Mes(head, 0), Mes(h, 0), tot = 0;
            n = strlen(ch + 1);
            last_d = Insert(1, n);
            scanf("%s
    ", ch + 1);
            m = strlen(ch + 1);
            Mes(f, 0);
            puts(Dfs(last_d.st, 1) ? "Yes" : "No");
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    新闻发布系统之 登陆注销
    readonly和const的区别
    c#中文件流的读写
    解决jsp两种提交方式乱码 的方法
    B/S 和 C/S两种架构
    App.config的典型应用
    接口实现多态
    Spring概念
    在Spring的核心配置文件applicationContext.xml中配置事务,主要配置三大方面:事务管理器、事务通知和定义事务性切面。
    乱码问题解决方案
  • 原文地址:https://www.cnblogs.com/zhouzj2004/p/13510284.html
Copyright © 2011-2022 走看看