feat: 添加三值逻辑问题解决方案及测试代码

实现P9869问题的解决方案,包含主逻辑处理文件和测试文件。主文件处理三值逻辑(T/F/U)的变量赋值和关系操作,测试文件提供更详细的实现和注释。添加路径压缩和环检测机制来正确处理逻辑依赖关系。
This commit is contained in:
Zengtudor 2025-10-25 20:24:35 +08:00
parent 5df5ae14a2
commit 413d070dbb
2 changed files with 173 additions and 0 deletions

76
src/10/25/P9869.cpp Normal file
View File

@ -0,0 +1,76 @@
#include <bitset>
#include <cstdint>
#include <iostream>
using ll = int64_t;
const ll maxn = 1e5+5;
const ll T=1e5+3,F=-1e5-3,U=0;
ll c,t,n,m,f[maxn];
std::bitset<2*maxn> vis;
#define vis(x)vis[(x)+n]
static inline ll find(ll x){
ll ret;
if(x==T||x==F)ret=x;
else if(vis(-x)||x==U){
ret=U;
}else if(vis(x))ret=T;
else if(x<0){
if(-f[-x] == x)ret=x;
else{
vis(x)=true;
f[-x]=ret=find(-f[-x]);
vis(x)=false;
}
}else{
if(f[x]==x)ret=x;
else{
vis(x)=true;
f[x]=ret=find(f[x]);
vis(x)=false;
}
}
return ret;
}
static inline void solve(){
vis.reset();
std::cin>>n>>m;
ll ans=0;
for(ll i=1;i<=n;i++)f[i]=i;
for(ll i=1;i<=m;i++){
char c;
std::cin>>c;
if(c=='T' || c=='F' || c=='U'){
ll v;
std::cin>>v;
switch (c) {
case 'T':f[v]=T;break;
case 'F':f[v]=F;break;
case 'U':f[v]=U;break;
}
}else if(c=='+'){
ll i,j;
std::cin>>i>>j;
f[i]=f[j];
}else if(c=='-'){
ll i,j;
std::cin>>i>>j;
f[i]=-f[j];
}
}
for(ll i=1;i<=n;i++){
ans+=find(i)==U;
}
std::cout<<ans<<"\n";
}
int main(){
std::iostream::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin>>c>>t;
while (t--) {
solve();
}
}

97
src/10/25/P9869t.cpp Normal file
View File

@ -0,0 +1,97 @@
#include<bits/stdc++.h>
#define int long long
using namespace std;
// 定义三个特殊值来表示三值逻辑
// 使用很大的数字来避免与普通变量下标冲突
const int T = 100001, F = -100001, U = 0; // T代表TrueF代表FalseU代表Unknown
int c, t, n, m, a, b, fa[100005]; // fa数组用于记录每个变量的当前值或依赖关系
char ch[100005]; // 存储每条语句的操作类型
bool book[300005]; // 标记数组,用于在递归查找时检测环
// 核心函数查找变量x的最终逻辑值
int find(int x) {
int re; // 返回值
// 情况1如果x已经是基础值(T/F/U),直接返回
if (x == T || x == F) re = x;
else if (book[n - x] || x == U) re = U;
// 这里book[n-x]是处理负数的标记x==U表示已经是Unknown
// 情况2如果x被标记为True在递归路径中
else if (book[x + n]) re = T;
// 情况3处理负数表示逻辑非操作的结果
else if (x < 0) {
// 如果负数指向自己,说明形成了自环,保持原值
if (x == -fa[-x]) re = x;
else {
book[x + n] = 1; // 标记当前节点,防止无限递归
// 递归查找:¬(¬A) = A所以这里取双重否定
re = find(-fa[-x]);
book[x + n] = 0; // 回溯,清空标记
}
}
// 情况4处理正数普通变量引用
else {
// 如果指向自己,说明是基础值或已确定的值
if (x == fa[x]) re = x;
else {
book[x + n] = 1; // 标记当前节点
// 递归查找依赖的值
re = fa[x] = find(fa[x]); // 路径压缩
book[x + n] = 0; // 回溯,清空标记
}
}
return re;
}
signed main() {
cin >> c >> t; // 读入测试点编号和数据组数
while (t--) {
cin >> n >> m; // 变量个数和语句条数
// 初始化:每个变量最初指向自己
for (int i = 1; i <= n; i++) fa[i] = i;
// 处理每条语句
for (int i = 1; i <= m; i++) {
cin >> ch[i]; // 读入操作类型
if (ch[i] == 'T') { // 赋值为True
cin >> a;
fa[a] = T; // 直接标记为T
}
else if (ch[i] == 'F') { // 赋值为False
cin >> a;
fa[a] = F; // 直接标记为F
}
else if (ch[i] == 'U') { // 赋值为Unknown
cin >> a;
fa[a] = U; // 直接标记为U
}
else {
cin >> a >> b;
if (ch[i] == '+') { // 赋值操作x_a ← x_b
fa[a] = fa[b]; // 直接复制值或引用
}
else { // 取反操作x_a ← ¬x_b
fa[a] = -fa[b]; // 用负数表示逻辑非
// 例如如果fa[b]=T(100001)那么fa[a]=-100001
// 这表示"非True"在find函数中会特殊处理
}
}
}
int ans = 0;
// 统计最终值为Unknown的变量个数
for (int i = 1; i <= n; i++) {
if (find(i) == U) ans++;
}
cout << ans << endl;
}
return 0;
}