一道关于表达式的题目。。。
思路参考了xhr大大的题解,在此贴上:
算法讨论
我们考虑一个宏是否是“安全”的,经过观察和一些实验,可以发现,只有以下4种状态:
•状态1(s1):这个宏完全安全,以任何方式使用该宏都没问题。
•状态2(s2):这个宏不安全,只要表达式中出现该宏,都会导致表达式不安全。
•状态3(s3):这个宏部分安全,仅当这个宏与’*’,’/’连接时,或出现在’-’后面时,才会使表达式不安全。
•状态4(s4):这个宏部分安全,仅当这个宏出现在’/’后面时,才会使表达式不安全。有了这4个状态,我们只需推出状态之间的转移即可。
•如果表达式没有使用任何运算符或括号或宏(也就是s仅仅是个单独的变量),那么安全级别显然是s1
•如果表达式s是(t)的形式(被一对括号括起来的表达式t),那么如果t的状态不是s2,则s的状态是s1,否则s的状态是s2
•我们找到表达式s中,最后一次运算的符号,设其为op,设其两侧表达式分别为t1和t2。我们进行以下分类讨论:
–显然,如果t1或t2的安全状态是s2,则s的状态也是s2;–如果op是’+’,那么s的状态是s3;
–如果op是’-’,那么,如t2状态是s3,则s状态是s2,否则s状态是s3
–如果op是’*’,那么,如t1或t2状态是s3,则s状态是s2,否则s状态是s4
–如果op是’/’,那么,如t1或t2状态是s3,或t2状态是s4,则s状态是s2,否则s状态是s4于是,此题得到了解决。时间复杂度O(n∗len2),如果愿意追求更好的复杂度,可以建出表达式树,从而做到O(N∗len)
实现时主要的点是先将表达式化作一个类似token流的东西,然后在其中找出最后一次运算(不是最后一个)的符号,根据两边的表达式类型递归求出整个表达式的类型
token流中1,2,3,4 表示 宏的四个状态;5,6,7,8表示+-*/
贴上代码:
#include <cstring> #include <iostream> #include <map> #include <algorithm> #include <stack> #include <string> #include <set> #include <cmath> #include <queue> #include <cstdio> #include <sstream> #include <vector> using namespace std; #define rep(i, j, k) for(int i = j; i <= k; i++) #define repm(i, j, k) for(int i = j; i >= k; i--) #define mem(a) memset(a, 0, sizeof(a)) #define mp make_pair typedef long long ll; int dx[4] = {0, 0, 1, -1}; int dy[4] = {1, -1, 0, 0}; char w[200]; string l; map<string, int> all; int msusp[200]; int as[110][110]; int ans(int l, int r, vector<int> vec) { if(l == r) return as[l][l] = vec[l]; if(as[l][r] != 0x7f7f7f7f) return as[l][r]; else { int id = l + 1; for(int i = l + 1; i < r; i += 2) { if(!(vec[id] <= 6 && vec[i] >= 7)) id = i; } if(ans(l, id - 1, vec) == 2 || ans(id + 1, r, vec) == 2) return as[l][r] = 2; if(vec[id] == 5) return as[l][r] = 3; if(vec[id] == 6) { if(ans(id + 1, r, vec) == 3) return as[l][r] = 2; return as[l][r] = 3; } else if(vec[id] == 7) { if(ans(l, id - 1, vec) == 3 || ans(id + 1, r, vec) == 3) return as[l][r] = 2; return as[l][r] = 4; } else if(vec[id] == 8) { if(ans(l, id - 1, vec) == 3 || ans(id + 1, r, vec) == 3 || ans(id + 1, r, vec) == 4) return as[l][r] = 2; return as[l][r] = 4; } } } int calc(int a, int b) { vector<int> vec; vec.clear(); int last = -1, susp = 0, d = 0; string cur = ""; rep(j, a, b) { if(j < b && (l[j] >= 'a' && l[j] <= 'z' || l[j] >= 'A' && l[j] <= 'Z' || l[j] >= '0' && l[j] <= '9')) cur += l[j]; else { if(cur != "") { if(d == 0) { int t = -1, csusp = 1; if(all.find(cur) != all.end()) { t = all[cur]; csusp = msusp[t]; } vec.push_back(csusp); } cur = ""; } } if(j == b) break; if(l[j] == '(') { if(d == 0) last = j + 1; d++; } if(l[j] == ')') { d--; if(d == 0) { int csusp = calc(last, j); if(csusp != 2) csusp = 1; vec.push_back(csusp); } } if(d == 0 && l[j] == '+') vec.push_back(5); if(d == 0 && l[j] == '-') vec.push_back(6); if(d == 0 && l[j] == '*') vec.push_back(7); if(d == 0 && l[j] == '/') vec.push_back(8); } memset(as,0x7f,sizeof(as)); return ans(0, vec.size() - 1, vec); } int n; int main() { scanf("%d\n",&n); rep(i, 0, n) { string s, ss; gets (w); istringstream in(w); if(i < n) { in >> s; if (s.size () == 1) in >> s; in >> s; } l = ""; while(in >> ss) l += ss; msusp[i] = calc(0, l.size()); if(i < n) all[s] = i; } if(msusp[n] != 2) cout << "OK" << endl; else cout << "Suspicious" << endl; }