Whispers of the Old Gods 题解

举报
炒香菇的书呆子 发表于 2022/01/24 23:46:46 2022/01/24
【摘要】 题目给定一个长度为 50005000 的正则表达式和一个长度为 1000010000 的文本串,求文本串最少修改多少次能够被正则表达式识别。 题解对正则表达式构造 NFA,令 f(l,i)f(l,i) 表达式使用完前 ll 个字符后,到达了 NFA 的状态 ii 时的最小修改次数,转移方程的形式为求一个 0/10/1 最短路。NFA 的构造,注意构造过程中不能随意删除中间的 ϵϵ 边:如果...

题目

给定一个长度为 50005000 的正则表达式和一个长度为 1000010000 的文本串,求文本串最少修改多少次能够被正则表达式识别。

题解

对正则表达式构造 NFA,令 f(l,i)f(l,i) 表达式使用完前 ll 个字符后,到达了 NFA 的状态 ii 时的最小修改次数,转移方程的形式为求一个 0/10/1 最短路。

NFA 的构造,注意构造过程中不能随意删除中间的 ϵϵ 边:

12

3

4

5

如果随意删除中间的 ϵϵ 边,可能会有如下的反例:

反例1

反例2

上图为 1+2+,而下图为 (1+2+)+

代码

#include <iostream>
#include <cassert>
#include <functional>
#include <algorithm>
#include <utility>
#include <vector>
#include <string>
#include <set>
#include <deque>
using namespace std;
using PII = pair<int,int>;
const int inf = 1 << 30;
const int maxn = 200000 + 5;

bool isDigit(char ch) {
  return '0' <= ch && ch <= '9';
}

using State = vector<PII>;

const int Epsilon = 0;

class Nfa : public vector<State> {
private:
  const string& pat;
  int cur = 0;

  int createState() {
    int root = size();
    push_back(State());
    return root;
  }

  PII parseAtom() {
    if (isDigit(pat[cur])) {
      int begin = createState();
      int end = createState();
      at(begin).emplace_back((int)pat[cur], end);
      cur++;
      return { begin, end };
    } else if (pat[cur] == '[') {
      cur++;
      int begin = createState();
      int end = createState();
      set<int> chs;
      while (cur < pat.length() && isDigit(pat[cur])) {
        chs.insert((int)pat[cur++]);
      }
      assert(pat[cur++] == ']');
      for (int ch: chs) at(begin).emplace_back(ch, end);
      return { begin, end };
    } else {
      assert(pat[cur++] == '(');
      auto node = parseAlt();
      assert(pat[cur++] == ')');
      return node;
    }
  }

  PII parseReg() {
    int begin = createState();
    int end = begin;
    auto peekPlus = [&]() {
      while (cur < pat.length() && pat[cur] == '+') cur++;
    };
    while (cur < pat.length() && (isDigit(pat[cur]) || pat[cur] == '[' || pat[cur] == '(')) {
      auto next = parseAtom();
      if (cur < pat.length() && pat[cur] == '+') {
        peekPlus();
        at(end).emplace_back(Epsilon, next.first);
        at(next.second).emplace_back(Epsilon, next.first);
        end = next.second;
      } else {
        at(end).emplace_back(Epsilon, next.first);
        end = next.second;
      }
    }
    return { begin, end };
  }

  PII parseAlt() {
    int begin = createState();
    auto next = parseReg();
    at(begin).emplace_back(Epsilon, next.first);
    vector<int> subEnd { next.second };
    while (cur < pat.length() && pat[cur] == '|') {
      cur++;
      auto next = parseReg();
      at(begin).emplace_back(Epsilon, next.first);
      subEnd.push_back(next.second);
    }
    int end = createState();
    for (auto& state: subEnd) {
      at(state).emplace_back(Epsilon, end);
    }
    return { begin, end };
  }

public:
  Nfa(const string& pat): pat(pat) {
    parseAlt();
  }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  string pat, str;
  cin >> pat >> str;

  Nfa nfa { pat };
  int nSz = nfa.size();
  int m = str.length();
  auto dis = vector<vector<int>>(nSz, vector<int>(m + 1, inf));
  deque<PII> dq;
  dis[0][0] = 0;
  dq.emplace_back(0, 0);

  while (!dq.empty()) {
    auto cur = dq.front();
    int cdis = dis[cur.first][cur.second];
    dq.pop_front();
    auto relaxFront = [&](int u, int l) {
      if (dis[u][l] > cdis) {
        dis[u][l] = cdis;
        dq.emplace_front(u, l);
      }
    };
    auto relaxBack = [&](int u, int l) {
      if (dis[u][l] > cdis + 1) {
        dis[u][l] = cdis + 1;
        dq.emplace_back(u, l);
      }
    };
    if (cur.second < m) {
      // delete
      relaxBack(cur.first, cur.second + 1);
    }
    for (auto& [ch, next]: nfa[cur.first]) {
      if (ch == Epsilon) {
        relaxFront(next, cur.second);
      } else {
        if (cur.second < m) {
          if (ch == str[cur.second]) {
            // match
            relaxFront(next, cur.second + 1);
          } else {
            // change
            relaxBack(next, cur.second + 1);
          }
        }
        // insert
        relaxBack(next, cur.second);
      }
    }
  }
  printf("%d\n", dis[nSz - 1][m]);
  return 0;
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。