1003 Reasoning(大模拟)
translation
现有一个推理系统,有如下符号组成:
- 圆括号:\((\) 和 \()\)
- 逻辑连词:\(\lnot\) 和 \(\to\)
- 全称量词:\(\forall\)
- 变量:\(u-z\)
- 常量:\(a-e\)
- 函数:\(f-h\)
- 谓词:\(P-T\)
这个推理系统还包括项(term)、公式(formula)、自由出现(free occurrence)和替换(replacement)等概念。基于这些概念,我们可以定义某个项 \(t\) 是否可以毫无冲突地替换某个变量 \(x\)。这是推理的基础之一,你想先解决这个问题。
项(term)的定义如下:
- 所有的变量 \(v\) 是一个项
- 所有的常量 \(c\) 是一个项
- 如果 \(t_1,t_2,\dots,t_n\) 是一些项,\(f\) 是一个函数,则 \(f_{t_1,t_2,\dots,t_n}\) 是一个项
公式(formula)的定义如下:
- 如果 \(t_1,t_2,\dots,t_n\) 是一些项,\(P\) 是一个谓词,则 \(P_{t_1,t_2,\dots,t_n}\) 是一个公式,而且这种公式被称为原子公式(atomic formula)
- 如果 \(\varphi\) 和 \(\psi\) 都是公式,则 \((\lnot\varphi)\) 和 \((\varphi\to\psi)\) 都是公式
- 如果 \(\varphi\) 是公式,\(v\) 是变量,则 \(\forall v\varphi\) 是公式
\(x\) 可以在 \(\varphi\) 中自由出现(free occurrence)的定义如下:
- 如果 \(\varphi\) 是原子公式,\(x\) 可以在 \(\varphi\) 中自由出现当且仅当在 \(\varphi\) 中有 \(x\)(可以理解为字符 \(x\) 在字符串 \(\varphi\) 中出现)
- 如果 \(\varphi\) 是 \((\lnot\psi)\),\(x\) 可以在 \(\varphi\) 中自由出现当且仅当 \(x\) 可以在 \(\psi\) 中自由出现
- 如果 \(\varphi\) 是 \((\psi\to\gamma)\),\(x\) 可以在 \(\varphi\) 中自由出现当且仅当 \(x\) 可以在 \(\psi\) 中自由出现或在 \(\gamma\) 中自由出现
- 如果 \(\varphi\) 是 \(\forall v\psi\),\(x\) 可以在 \(\varphi\) 中自由出现当且仅当 \(x\) 可以在 \(\psi\) 中自由出现且 \(x\neq v\)
对于所有公式 \(\varphi\),变量 \(x\),项 \(t\),替换(replacement)\(\varphi^x_t\) 的定义如下:
- 如果 \(\varphi\) 是原子公式,那么 \(\varphi^x_t\) 是通过简单地将每个字符 \(x\) 替换为字符串 \(t\) 形成的表达式
- 如果 \(\varphi\) 是 \((\lnot\psi)\),那么 \((\lnot\psi)^x_t=(\lnot\psi^x_t)\)
- 如果 \(\varphi\) 是 \((\psi\to\gamma)\),那么 \((\psi\to\gamma)^x_t=(\psi^x_t\to\gamma^x_t)\)
- 如果 \(\varphi\) 是 \(\forall y\psi\),那么 \((\forall y\psi)^x_t=\left\{\begin{array}{ll}\forall y(\psi^x_t) & & \text{if}\ x\neq y\\\forall y\psi & & \text{if}\ x=y\end{array}\right.\)
最后,无冲突替换的定义如下:
- 如果 \(\varphi\) 是原子公式,那么 \(t\) 始终可以在 \(\varphi\) 中无冲突替换 \(x\)
- 如果 \(\varphi\) 是 \((\lnot\psi)\),那么 \(t\) 在 \(\varphi\) 中可以无冲突替换 \(x\) 当且仅当 \(t\) 在 \(\psi\) 中可以无冲突替换 \(x\)
- 如果 \(\varphi\) 是 \((\psi\to\gamma)\),那么 \(t\) 在 \(\varphi\) 中可以无冲突替换 \(x\) 当且仅当 \(t\) 在 \(\psi\) 和 \(\gamma\) 中都可以无冲突替换 \(x\)
- 如果 \(\varphi\) 是 \(\forall y\psi\),那么 \(t\) 在 \(\varphi\) 中可以无冲突替换 \(x\) 当且仅当:
- \(x\) 不能在 \(\varphi\) 中自由出现,或
- \(y\) 不能在 \(t\) 中自由出现,且 \(t\) 在 \(\psi\) 中可以无冲突替换 \(x\)
现在,你需要判断项 \(t\) 是否可以无冲突替换 \(x\)
solution
模拟即可。
在代码实现上,我忽略了所有 \()\) 和 \(\to\),然后把左括号当做一个有 2 个参数的函数,把 \(\lnot\) 当成一个没有参数的函数,最后把所有变量和常量都当成没有参数的函数,这样整个公式中就只有谓语,函数和 \(\forall\),可以一起实现。
code
#define pb push_back
int T; string s; int m, num[300]; int q; bool v[120][6]; int fa[120];
bool vis[6];
bool IS (char c) {return (c >= 'f' && c <= 'h') || (c >= 'P' && c <= 'T') || (c == '(');}
bool az[120];
void Find (int a, int id) {
RI i, j; az[id] = 1; int lst = id; for (i = 1; i <= a; ++ i) {
W (az[id]) ++ id; fa[id] = lst; Find (num[s[id]], id);
}
}
bool qus[11];
int main () {
RI i, j; Read (T); W (T --) {
Mt (fa, -1); Mt (az, 0); Mt (num, 0); Mt (v, 0);
cin >> s; int n = s.length (); s = " " + s; Read (m);
for (i = 1; i <= m; ++ i) {char c; int x; Readc (c); Read (x); num[c] = x;} num['('] = 2;
for (i = 1; i <= n; ++ i) if (s[i] == 'I' || s[i] == ')' || s[i] == 'A' || s[i - 1] == 'A') az[i] = 1;
for (i = 1; i <= n; ++ i) if (IS (s[i])) {Find (num[s[i]], i); break;}
bool flag = 0; for (i = 1; i <= n; ++ i) {
if (s[i] == 'A') {vis[s[i + 1] - 'u'] = 1; ++ i; flag = 1;}
else if (flag == 1) {for (j = 0; j <= 5; ++ j) v[i][j] |= vis[j]; Mt (vis, 0); flag = 0;}
} for (i = 1; i <= n; ++ i) {
if (fa[i] == -1) continue; for (j = 0; j <= 5; ++ j) v[i][j] |= v[fa[i]][j];
}
Read (q); W (q --) {
string ca; char c; cin >> ca; Readc (c); int len = ca.length (); Mt (qus, 0);
for (i = 0; i < len; ++ i) {
if (ca[i] >= 'a' && ca[i] <= 'e') qus[ca[i] - 'a'] = 1;
if (ca[i] >= 'u' && ca[i] <= 'z') qus[ca[i] - 'u' + 5] = 1;
}
bool YN = 1; for (i = 1; i <= n; ++ i) {
if (s[i] != c) continue;
if (fa[i] == -1) continue;
if (v[i][c - 'u'] == 1) continue;
for (j = 0; j <= 5; ++ j) {
if (v[i][j] && qus[j + 5]) {YN = 0; break;}
}
}
putchar (YN ? 'Y' : 'N'); printf ("\n"); if (! YN) continue;
for (i = 1; i <= n; ++ i) {
if (s[i] != c) printf ("%c", s[i]);
else if (v[i][c - 'u'] == 1) printf ("%c", s[i]);
else if (fa[i] == -1) printf ("%c", s[i]);
else printf ("%s", ca.c_str ());
} printf ("\n");
}
}
return 0;
}