题意

输入两个正规表达式,判断两者是否相交(即存在一个串同时满足两个正规表达式)。本题的正规表达式包含如下几种情况:

  • 单个小写字符 $c$
  • 或:($P | Q$). 如果字符串 $s$ 满足 $P$ 或者满足 $Q$,则 $s$ 满足 $(P| Q)$
  • 连接:($PQ$). 如果字符串 $s_1$ 满足 $P$,$s_2$ 满足 $Q$,则 $s_1s_2$ 满足 $(PQ)$
  • 克莱因闭包:$(P^*)$. 如果字符串 $s$ 可以写成0个或多个字符串 $s_i$ 的连接 $s_1s_2...$,且每个串都满足 $P$,则 $s$ 满足 $(P^*)$。注意,空串也满足 $(P^*)$

分析

先把每种情况都转成自动机,正则表达式也就是这些自动机的组合。都转成 NFA,再使用DFS或BFS寻找一个同时被两个自动机接受的非空串。

码力不够啊(平常的模拟题都是交给队友做的),下面给出 lrj 的代码,%%%。

(好像UVa上这题数据错了,已经两年没人AC。

// UVa1672 Disjoint Regular Expressions
// Rujia Liu
//
// This is Problem 12-2 of <<Beginning Algorithm Contests>> 2nd edition
//
// This code is neither simplest nor most efficient, but it's easy to understand and fast enough.
// Algorithm implemented here:
// 1. build epsilon-NFA from the regex
// 2. build NFA by removing epsilon from epsilon-NFA. Note that we did NOT optimize the epsilon-NFA as described in the book.
// 3. use BFS to find a common string of these two NFAs
// Attention: the output should NOT be empty so we used a little trick.
//
// Alternative algorithm: do BFS directly on epsilon-NFAs.
// State is (s1,s2,b) where b=1 iff at least one non-epsilon transition is performed.
// However, this graph is now 0-1 weighted so we need to use deque (or two-phase BFS).
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<string>
#include<queue>
#include<cassert>
#define REP(i,n) for(int i = 0; i < (n); ++i) using namespace std; // Part I: Expression Parser
struct ExprNode {
enum {A, STAR, OR, CONCAT};
int type, val;
ExprNode *l, *r; ExprNode(int type, ExprNode* l, ExprNode* r, int val = -):type(type),l(l),r(r),val(val){}
~ExprNode() {
if(l) delete l;
if(r) delete r;
}
}; struct Parser {
char* s;
int p, n; void Skip(char c) { p++; } // for debug purpose // (u)*
ExprNode* Item() {
ExprNode* u;
if(s[p] == '(') { Skip('('); u = Expr(); Skip(')'); }
else u = new ExprNode(ExprNode::A, NULL, NULL, s[p++]);
while(s[p] == '*') {
Skip('*');
u = new ExprNode(ExprNode::STAR, u, NULL);
}
return u;
} // u1u2u3...
ExprNode* Concat() {
ExprNode* u = Item();
while(s[p] && s[p] != ')' && s[p] != '|')
u = new ExprNode(ExprNode::CONCAT, u, Item());
return u;
} // u1|u2|u3
ExprNode* Expr() {
ExprNode* u = Concat();
while(s[p] == '|') {
Skip('|');
u = new ExprNode(ExprNode::OR, u, Concat());
}
return u;
} ExprNode* parse(char* str) {
s = str;
n = strlen(s);
p = ;
return Expr();
} }; // Part II: NFA construction
const int maxs = * + ; struct NFA {
int n; // number of states struct Transition {
int ch, next;
Transition(int ch = , int next = ):ch(ch),next(next){}
bool operator < (const Transition& rhs) const {
if(ch != rhs.ch) return ch < rhs.ch;
return next < rhs.next;
}
};
vector<Transition> trans[maxs]; void add(int s, int t, int c) {
trans[s].push_back(Transition(c, t));
} void process(ExprNode* u) {
int st = n++; // state 'start'
if(u->type == ExprNode::A) add(st, n, u->val);
else if(u->type == ExprNode::STAR) {
process(u->l);
add(st, st+, -);
add(st, n, -);
add(n-, st, -);
}
else if(u->type == ExprNode::OR) {
process(u->l);
int m = n;
process(u->r);
add(st, st+, -);
add(st, m, -);
add(m-, n, -);
add(n-, n, -);
}
else if(u->type == ExprNode::CONCAT) {
add(st, st+, -);
process(u->l);
add(n-, n, -);
process(u->r);
add(n-, n, -);
}
n++; // state 'end'
} void init(char* s) {
Parser p;
ExprNode* root = p.parse(s);
n = ;
for(int i = ; i < maxs; i++) {
trans[i].clear();
}
process(root);
delete root;
} vector<int> ss; // starting states void remove_epsilon() {
// find epsilon-closure for each state
vector<int> reachable[maxs];
int vis[maxs];
for(int i = ; i < n; i++) {
reachable[i].clear();
reachable[i].push_back(i);
queue<int> q;
q.push(i);
memset(vis, , sizeof(vis));
vis[i] = ;
while(!q.empty()) {
int s = q.front(); q.pop();
for(int j = ; j < trans[s].size(); j++)
if(trans[s][j].ch == -) {
int s2 = trans[s][j].next;
if(!vis[s2]) {
reachable[i].push_back(s2);
vis[s2] = ;
q.push(s2);
}
}
}
}
ss = reachable[]; // merge transitions
for(int i = ; i < n; i++) {
set<Transition> tr;
for(int j = ; j < trans[i].size(); j++) {
if(trans[i][j].ch == -) continue;
int s = trans[i][j].next;
for(int k = ; k < reachable[s].size(); k++)
tr.insert(Transition(trans[i][j].ch, reachable[s][k]));
}
trans[i] = vector<Transition>(tr.begin(), tr.end());
}
}
}; // Part III: BFS to find the answer const int maxn = + ;
const int maxq = * * * * + ; // case 26
char sa[maxn], sb[maxn]; struct State {
int s1, s2, fa, ch;
} states[maxq];
int ns; void print_solution(int s) {
if(states[s].fa == -) return;
print_solution(states[s].fa);
printf("%c", states[s].ch);
} void solve(const NFA& A, const NFA& B) {
queue<int> q;
int vis[maxs][maxs];
memset(vis, , sizeof(vis));
ns = ;
REP(i, A.ss.size())
REP(j, B.ss.size()) {
int s1 = A.ss[i], s2 = B.ss[j];
states[ns].s1 = s1;
states[ns].s2 = s2;
states[ns].fa = -;
q.push(ns++);
} while(!q.empty()) {
int s = q.front(); q.pop();
int s1 = states[s].s1;
int s2 = states[s].s2;
if(s1 == A.n- && s2 == B.n- && states[s].fa != -) {
printf("Wrong\n");
print_solution(s);
printf("\n");
return;
}
int n1 = A.trans[s1].size();
int n2 = B.trans[s2].size(); REP(i, n1) REP(j, n2)
if(A.trans[s1][i].ch == B.trans[s2][j].ch) {
int s1b = A.trans[s1][i].next;
int s2b = B.trans[s2][j].next;
int c = A.trans[s1][i].ch;
if(vis[s1b][s2b]) continue;
vis[s1b][s2b] = ;
states[ns].s1 = s1b;
states[ns].s2 = s2b;
states[ns].fa = s;
states[ns].ch = c;
q.push(ns++);
}
}
printf("Correct\n");
} NFA A, B;
int main() {
while(scanf("%s%s", sa, sb) == ) {
A.init(sa);
B.init(sb);
A.remove_epsilon();
B.remove_epsilon();
solve(A, B);
}
return ;
}

l

UVA 1672不相交的正规表达式的更多相关文章

  1. 学JS的心路历程-正规表达式Regular Expression

    今天我们来看正规表达式,在谈到为什么需要多学这个之前,先来看个示例. 假设需要判断输入字串是否含有“apple”: var text=“A apple a day keeps the doctor a ...

  2. 正规表达式 转 NFA C++

    今天来为大家分享一个编译原理中用正规表达式转NFA的小程序 正规表达式就是类似正则一样的式子,例如:(a|b)*abb,最后应该转化为: 大致的处理流程为: 例子中的表达式:(a|b)*abb,|和* ...

  3. 1.java实现——正规表达式判断

    目标:这个代码仅局限于所展示的正规表达式判断,也就是这是一个较单一的正规表达式判断(简易版). 既然是简易版的,所以若要修改这个正规表达式也是非常容易的,只要将二维数组中的数组修改即可.数组数据依据, ...

  4. 正规表达式与有限自动机和LEX

    正规式与有限自动机的等价性 一个正规式r与一个有限自动机M等价, L(r)=L(M) FA ->正规式,对任何FA M,都存在一个正规式r,使得L(r)=L(M). 正规式 -> FA, ...

  5. Linux学习十七、正规表达式练习题

    情境模拟题一:透过 grep 搜寻特殊字串,并配合数据流重导向来处理大量的文件搜寻问题. 目标:正确的使用正规表示法: 前提:需要了解数据流重导向,以及透过子命令 $(command) 来处理档名的搜 ...

  6. UVA 1661 Equation (后缀表达式,表达式树,模拟,实现)

    题意:给出一个后缀表达式f(x),最多出现一次x,解方程f(x) = 0. 读取的时候用一个栈保存之前的结点,可以得到一颗二叉树,标记出现'X'的路径,先把没有出现'X'的子树算完,由于读取建树的时候 ...

  7. 轻松学Shell之认识正规表达式

    离线下载观看:http://down.51cto.com/data/148117   650) this.width=650;" onclick='window.open("htt ...

  8. vs 2017 正规表达式替换整行多行数据

    ((<OutputFile>..*</OutputFile>)[\S\s])[\S\s] 从 <OutputFile> 开始 到 </OutputFile&g ...

  9. Swift中用正规表达式判断String是否是手机号码

    func isTelNumber(num:NSString)->Bool { var mobile = "^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$&qu ...

随机推荐

  1. LeetCode 75. 颜色分类(Sort Colors) 30

    75. 颜色分类 75. Sort Colors 题目描述 给定一个包含红色.白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色.白色.蓝色顺序排列. 此题中, ...

  2. 为什么Apache Kafka如此受欢迎

    1.目标 今天,在这个Kafka教程中,我们将学习所有Kafka功能,如可扩展性,可靠性,耐用性,这些都说明了Kafka如此受欢迎的原因.我们将详细讨论Kafka的每个功能.但在那之前让我们明白什么是 ...

  3. Java开发笔记(一百二十七)Swing的标签

    提起AWT的标签控件Label,那个使用体验可真叫糟糕,不但不支持文字换行,而且对中文很不友好,既可能把中文显示为乱码,还不支持博大精深的各种中文字体.所幸Swing的升级版标签JLabel在各方面都 ...

  4. 19 IO流(十六)——Commons工具包,FileUtils(一)

    Commons包的API:自己查吧懒得传云 Commons包的导入方法 Commons是一个java的IO开源工具,导入方法: 从apache.org下载commons包 解压 copy其中的comm ...

  5. 【微信小程序学习笔记】入门与了解

    [微信小程序学习笔记(一)] IDE 下载安装 下载地址 官方工具:https://mp.weixin.qq.com/debug/w … tml?t=1476434678461 下载可执行文件后,可按 ...

  6. Flask总结篇

    1 Flask框架的优势? 相信做Python这一块的程序员都有听说这三个框架,就像神一样的存在,每一个框架的介绍我就不写出来了,感兴趣可以自己百度了解了解!下面我就说正事 Django:Python ...

  7. 转 让NET C# 程序独立运行(脱离 .NET Framework运行,绿色运行) 未验证

    但是.net版本众多.而且.NET Framework框架很大.拖着一个大大的.net Framework总是让人很郁闷. 在网上找呀找呀.找到另一个.NET Framework 替代方案.Mono. ...

  8. python3--说简单也不简单的排序算法

    在刚开始接触算法时,我们可能一脸懵,不知从何处下手,尤其是现在使用的语言五花八门,各种语言的实现又不尽相同,所以,在这种情况下,千万不能迷失了自己,掌握了算法的原理,就像解数学公式一样,定理给你了,仔 ...

  9. 【洛谷 P4254】 [JSOI2008]Blue Mary开公司(李超线段树)

    题目链接 其实这东西很好懂的..用来维护一次函数. 每个结点存一个值,表示x=这个区间的mid时值最大的函数的编号. 把插入线段的斜率和当前结点的斜率和大小比较来更新左右儿子的值. 查询是实际上是查询 ...

  10. C++线程同步之临界区

    #include <iostream> #include <windows.h> using namespace std; CRITICAL_SECTION cs; // Lo ...