UVA 1672不相交的正规表达式
题意
输入两个正规表达式,判断两者是否相交(即存在一个串同时满足两个正规表达式)。本题的正规表达式包含如下几种情况:
- 单个小写字符 $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不相交的正规表达式的更多相关文章
- 学JS的心路历程-正规表达式Regular Expression
今天我们来看正规表达式,在谈到为什么需要多学这个之前,先来看个示例. 假设需要判断输入字串是否含有“apple”: var text=“A apple a day keeps the doctor a ...
- 正规表达式 转 NFA C++
今天来为大家分享一个编译原理中用正规表达式转NFA的小程序 正规表达式就是类似正则一样的式子,例如:(a|b)*abb,最后应该转化为: 大致的处理流程为: 例子中的表达式:(a|b)*abb,|和* ...
- 1.java实现——正规表达式判断
目标:这个代码仅局限于所展示的正规表达式判断,也就是这是一个较单一的正规表达式判断(简易版). 既然是简易版的,所以若要修改这个正规表达式也是非常容易的,只要将二维数组中的数组修改即可.数组数据依据, ...
- 正规表达式与有限自动机和LEX
正规式与有限自动机的等价性 一个正规式r与一个有限自动机M等价, L(r)=L(M) FA ->正规式,对任何FA M,都存在一个正规式r,使得L(r)=L(M). 正规式 -> FA, ...
- Linux学习十七、正规表达式练习题
情境模拟题一:透过 grep 搜寻特殊字串,并配合数据流重导向来处理大量的文件搜寻问题. 目标:正确的使用正规表示法: 前提:需要了解数据流重导向,以及透过子命令 $(command) 来处理档名的搜 ...
- UVA 1661 Equation (后缀表达式,表达式树,模拟,实现)
题意:给出一个后缀表达式f(x),最多出现一次x,解方程f(x) = 0. 读取的时候用一个栈保存之前的结点,可以得到一颗二叉树,标记出现'X'的路径,先把没有出现'X'的子树算完,由于读取建树的时候 ...
- 轻松学Shell之认识正规表达式
离线下载观看:http://down.51cto.com/data/148117 650) this.width=650;" onclick='window.open("htt ...
- vs 2017 正规表达式替换整行多行数据
((<OutputFile>..*</OutputFile>)[\S\s])[\S\s] 从 <OutputFile> 开始 到 </OutputFile&g ...
- Swift中用正规表达式判断String是否是手机号码
func isTelNumber(num:NSString)->Bool { var mobile = "^1(3[0-9]|5[0-35-9]|8[025-9])\\d{8}$&qu ...
随机推荐
- postman上传文件对参数的contentType类型设置方式
项目中使用postman模拟上传文件接口时,总是不成功,发现content-type设置不对,设置head的contentType后,还是不行,后来无意中发现文件参数默认的content-type类型 ...
- spring整合quartz报错
今天spring整合quartz报错,最后一步步排查,发现是和redis依赖冲突,最后redis升级了一下,问题解决. 总结:发现问题,逐一排查,如果是整合问题,报类加载不到的错误,大概率是和其他组件 ...
- DP(动态规划)总结
前言 动态规划是很重要的一个知识点,大大小小的比赛总会有一两道DP题,足以说明动态规划的重要性. 动态规划主要是思想,并没有固定的模板,那么,怎么判断题目是不是动态规划呢? DP题一般都会满足三个条件 ...
- tft_LCD一些引脚极性设置方法:vsync, hsync, VBLANK
转载:https://blog.csdn.net/u014170207/article/details/52662988/ 在RGB模式中,LCD数据的扫描是以行为单位的.HSYNC是水平同步信号.P ...
- Django模型层之ORM
Django模型层之ORM操作 一 ORM简介 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数据库管理软 ...
- spring boot + vue实现图片上传及展示
转载:https://blog.csdn.net/weixin_40337982/article/details/84031778 其中一部分对我很有帮助 转载记录下 首先,html页面: <! ...
- .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
原文:.NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态 在 Windows 系统中,一段时间不操作键盘和鼠标,屏幕便会关闭,系统会进入睡眠状态.但有些程序(比如游戏.视频和演示文稿)在运行过程中应该 ...
- 2.3_Database Interface ODBC组成原理
从某种意义上来讲,ODBC实际上主要是一个数据库的访问库(API),它包含访问不同数据库所要求的ODBC驱动程序.应用程序要操作不同类型的数据库,只要调用ODBC所支持的函数,动态链接到不同的驱动程序 ...
- ADO.NET 二(Connection)
C# 语言中 Connection 类是 ADO.NET 组件连接数据库时第一个要使用的类,也是通过编程访问数据库的第一步. 接下来了解一下 Connection 类中的常用属性和方法,以及如何连接 ...
- MySQL比较时间(datetime)大小
获取时间返回的秒数:strtotime('2019-05-10 00:00:00') 遇到一个业务功能需要将当前时间与数据库中的会议开始.结束时间进行比较,记录一下,方便下次用. 用unix_time ...