题意

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

  • 单个小写字符 $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。

  1. // UVa1672 Disjoint Regular Expressions
  2. // Rujia Liu
  3. //
  4. // This is Problem 12-2 of <<Beginning Algorithm Contests>> 2nd edition
  5. //
  6. // This code is neither simplest nor most efficient, but it's easy to understand and fast enough.
  7. // Algorithm implemented here:
  8. // 1. build epsilon-NFA from the regex
  9. // 2. build NFA by removing epsilon from epsilon-NFA. Note that we did NOT optimize the epsilon-NFA as described in the book.
  10. // 3. use BFS to find a common string of these two NFAs
  11. // Attention: the output should NOT be empty so we used a little trick.
  12. //
  13. // Alternative algorithm: do BFS directly on epsilon-NFAs.
  14. // State is (s1,s2,b) where b=1 iff at least one non-epsilon transition is performed.
  15. // However, this graph is now 0-1 weighted so we need to use deque (or two-phase BFS).
  16. #include<cstdio>
  17. #include<cstring>
  18. #include<vector>
  19. #include<set>
  20. #include<string>
  21. #include<queue>
  22. #include<cassert>
  23. #define REP(i,n) for(int i = 0; i < (n); ++i)
  24.  
  25. using namespace std;
  26.  
  27. // Part I: Expression Parser
  28. struct ExprNode {
  29. enum {A, STAR, OR, CONCAT};
  30. int type, val;
  31. ExprNode *l, *r;
  32.  
  33. ExprNode(int type, ExprNode* l, ExprNode* r, int val = -):type(type),l(l),r(r),val(val){}
  34. ~ExprNode() {
  35. if(l) delete l;
  36. if(r) delete r;
  37. }
  38. };
  39.  
  40. struct Parser {
  41. char* s;
  42. int p, n;
  43.  
  44. void Skip(char c) { p++; } // for debug purpose
  45.  
  46. // (u)*
  47. ExprNode* Item() {
  48. ExprNode* u;
  49. if(s[p] == '(') { Skip('('); u = Expr(); Skip(')'); }
  50. else u = new ExprNode(ExprNode::A, NULL, NULL, s[p++]);
  51. while(s[p] == '*') {
  52. Skip('*');
  53. u = new ExprNode(ExprNode::STAR, u, NULL);
  54. }
  55. return u;
  56. }
  57.  
  58. // u1u2u3...
  59. ExprNode* Concat() {
  60. ExprNode* u = Item();
  61. while(s[p] && s[p] != ')' && s[p] != '|')
  62. u = new ExprNode(ExprNode::CONCAT, u, Item());
  63. return u;
  64. }
  65.  
  66. // u1|u2|u3
  67. ExprNode* Expr() {
  68. ExprNode* u = Concat();
  69. while(s[p] == '|') {
  70. Skip('|');
  71. u = new ExprNode(ExprNode::OR, u, Concat());
  72. }
  73. return u;
  74. }
  75.  
  76. ExprNode* parse(char* str) {
  77. s = str;
  78. n = strlen(s);
  79. p = ;
  80. return Expr();
  81. }
  82.  
  83. };
  84.  
  85. // Part II: NFA construction
  86. const int maxs = * + ;
  87.  
  88. struct NFA {
  89. int n; // number of states
  90.  
  91. struct Transition {
  92. int ch, next;
  93. Transition(int ch = , int next = ):ch(ch),next(next){}
  94. bool operator < (const Transition& rhs) const {
  95. if(ch != rhs.ch) return ch < rhs.ch;
  96. return next < rhs.next;
  97. }
  98. };
  99. vector<Transition> trans[maxs];
  100.  
  101. void add(int s, int t, int c) {
  102. trans[s].push_back(Transition(c, t));
  103. }
  104.  
  105. void process(ExprNode* u) {
  106. int st = n++; // state 'start'
  107. if(u->type == ExprNode::A) add(st, n, u->val);
  108. else if(u->type == ExprNode::STAR) {
  109. process(u->l);
  110. add(st, st+, -);
  111. add(st, n, -);
  112. add(n-, st, -);
  113. }
  114. else if(u->type == ExprNode::OR) {
  115. process(u->l);
  116. int m = n;
  117. process(u->r);
  118. add(st, st+, -);
  119. add(st, m, -);
  120. add(m-, n, -);
  121. add(n-, n, -);
  122. }
  123. else if(u->type == ExprNode::CONCAT) {
  124. add(st, st+, -);
  125. process(u->l);
  126. add(n-, n, -);
  127. process(u->r);
  128. add(n-, n, -);
  129. }
  130. n++; // state 'end'
  131. }
  132.  
  133. void init(char* s) {
  134. Parser p;
  135. ExprNode* root = p.parse(s);
  136. n = ;
  137. for(int i = ; i < maxs; i++) {
  138. trans[i].clear();
  139. }
  140. process(root);
  141. delete root;
  142. }
  143.  
  144. vector<int> ss; // starting states
  145.  
  146. void remove_epsilon() {
  147. // find epsilon-closure for each state
  148. vector<int> reachable[maxs];
  149. int vis[maxs];
  150. for(int i = ; i < n; i++) {
  151. reachable[i].clear();
  152. reachable[i].push_back(i);
  153. queue<int> q;
  154. q.push(i);
  155. memset(vis, , sizeof(vis));
  156. vis[i] = ;
  157. while(!q.empty()) {
  158. int s = q.front(); q.pop();
  159. for(int j = ; j < trans[s].size(); j++)
  160. if(trans[s][j].ch == -) {
  161. int s2 = trans[s][j].next;
  162. if(!vis[s2]) {
  163. reachable[i].push_back(s2);
  164. vis[s2] = ;
  165. q.push(s2);
  166. }
  167. }
  168. }
  169. }
  170. ss = reachable[];
  171.  
  172. // merge transitions
  173. for(int i = ; i < n; i++) {
  174. set<Transition> tr;
  175. for(int j = ; j < trans[i].size(); j++) {
  176. if(trans[i][j].ch == -) continue;
  177. int s = trans[i][j].next;
  178. for(int k = ; k < reachable[s].size(); k++)
  179. tr.insert(Transition(trans[i][j].ch, reachable[s][k]));
  180. }
  181. trans[i] = vector<Transition>(tr.begin(), tr.end());
  182. }
  183. }
  184. };
  185.  
  186. // Part III: BFS to find the answer
  187.  
  188. const int maxn = + ;
  189. const int maxq = * * * * + ; // case 26
  190. char sa[maxn], sb[maxn];
  191.  
  192. struct State {
  193. int s1, s2, fa, ch;
  194. } states[maxq];
  195. int ns;
  196.  
  197. void print_solution(int s) {
  198. if(states[s].fa == -) return;
  199. print_solution(states[s].fa);
  200. printf("%c", states[s].ch);
  201. }
  202.  
  203. void solve(const NFA& A, const NFA& B) {
  204. queue<int> q;
  205. int vis[maxs][maxs];
  206. memset(vis, , sizeof(vis));
  207. ns = ;
  208. REP(i, A.ss.size())
  209. REP(j, B.ss.size()) {
  210. int s1 = A.ss[i], s2 = B.ss[j];
  211. states[ns].s1 = s1;
  212. states[ns].s2 = s2;
  213. states[ns].fa = -;
  214. q.push(ns++);
  215. }
  216.  
  217. while(!q.empty()) {
  218. int s = q.front(); q.pop();
  219. int s1 = states[s].s1;
  220. int s2 = states[s].s2;
  221. if(s1 == A.n- && s2 == B.n- && states[s].fa != -) {
  222. printf("Wrong\n");
  223. print_solution(s);
  224. printf("\n");
  225. return;
  226. }
  227. int n1 = A.trans[s1].size();
  228. int n2 = B.trans[s2].size();
  229.  
  230. REP(i, n1) REP(j, n2)
  231. if(A.trans[s1][i].ch == B.trans[s2][j].ch) {
  232. int s1b = A.trans[s1][i].next;
  233. int s2b = B.trans[s2][j].next;
  234. int c = A.trans[s1][i].ch;
  235. if(vis[s1b][s2b]) continue;
  236. vis[s1b][s2b] = ;
  237. states[ns].s1 = s1b;
  238. states[ns].s2 = s2b;
  239. states[ns].fa = s;
  240. states[ns].ch = c;
  241. q.push(ns++);
  242. }
  243. }
  244. printf("Correct\n");
  245. }
  246.  
  247. NFA A, B;
  248. int main() {
  249. while(scanf("%s%s", sa, sb) == ) {
  250. A.init(sa);
  251. B.init(sb);
  252. A.remove_epsilon();
  253. B.remove_epsilon();
  254. solve(A, B);
  255. }
  256. return ;
  257. }

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. postman上传文件对参数的contentType类型设置方式

    项目中使用postman模拟上传文件接口时,总是不成功,发现content-type设置不对,设置head的contentType后,还是不行,后来无意中发现文件参数默认的content-type类型 ...

  2. spring整合quartz报错

    今天spring整合quartz报错,最后一步步排查,发现是和redis依赖冲突,最后redis升级了一下,问题解决. 总结:发现问题,逐一排查,如果是整合问题,报类加载不到的错误,大概率是和其他组件 ...

  3. DP(动态规划)总结

    前言 动态规划是很重要的一个知识点,大大小小的比赛总会有一两道DP题,足以说明动态规划的重要性. 动态规划主要是思想,并没有固定的模板,那么,怎么判断题目是不是动态规划呢? DP题一般都会满足三个条件 ...

  4. tft_LCD一些引脚极性设置方法:vsync, hsync, VBLANK

    转载:https://blog.csdn.net/u014170207/article/details/52662988/ 在RGB模式中,LCD数据的扫描是以行为单位的.HSYNC是水平同步信号.P ...

  5. Django模型层之ORM

    Django模型层之ORM操作 一 ORM简介 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数据库管理软 ...

  6. spring boot + vue实现图片上传及展示

    转载:https://blog.csdn.net/weixin_40337982/article/details/84031778 其中一部分对我很有帮助 转载记录下 首先,html页面: <! ...

  7. .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态

    原文:.NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态 在 Windows 系统中,一段时间不操作键盘和鼠标,屏幕便会关闭,系统会进入睡眠状态.但有些程序(比如游戏.视频和演示文稿)在运行过程中应该 ...

  8. 2.3_Database Interface ODBC组成原理

    从某种意义上来讲,ODBC实际上主要是一个数据库的访问库(API),它包含访问不同数据库所要求的ODBC驱动程序.应用程序要操作不同类型的数据库,只要调用ODBC所支持的函数,动态链接到不同的驱动程序 ...

  9. ADO.NET 二(Connection)

    C# 语言中 Connection 类是 ADO.NET 组件连接数据库时第一个要使用的类,也是通过编程访问数据库的第一步. 接下来了解一下 Connection 类中的常用属性和方法,以及如何连接 ...

  10. MySQL比较时间(datetime)大小

    获取时间返回的秒数:strtotime('2019-05-10 00:00:00') 遇到一个业务功能需要将当前时间与数据库中的会议开始.结束时间进行比较,记录一下,方便下次用. 用unix_time ...