NOIP2023第2题&洛谷P9869三值逻辑题解

8 篇文章 0 订阅
3 篇文章 0 订阅

题目链接

同P9868一样,后面可能会修改链接
直击题目
那我们开始吧

题目分析

嗯,这道题描述的还是比较清晰的,但是还可以再转化几步。
那怎么让U最小呢?我们好像从问题出发不了。我们要不先把问题晾在一边。
我们来看条件吧,我们要满足的是所有变量的最终值和初始值相等。
所以这道题其实是两个部分:

  1. 求出所有变量最终值的表示
  2. 给所有变量的初值赋值,让所有变量最终值和初值相等,而且U的变量最小

现在明显多了吧。

题目思路

前置知识

在这之前,如果你想看懂题目的代码,你需要会并查集不会吧,不会吧,不会还有人不会并查集吧
当然,为了防止有人不会并查集,我依然决定真诚地把并查集的博客放在这里。
学会了吗?我们继续吧。

第一部分

我们按顺序先来解决求出所有变量最终值的表示这个问题。
为什么要加上“的表示”呢?因为我们一开始并不知道所有变量的初始值是什么样子才能让U的值最小并满足条件。

表示的构造

但是没有关系,我们可以把所有变量的初始值当成一个逻辑值。下面是我的构造:(先说好,第 i i i个变量的初始值记为 x i x_i xi,目前值记为 y i y_i yi
如果第 i i i个值的目前的值根据赋值关系与 x i x_i xi的初始值相同,那么 y i = i y_i=i yi=i
如果第 i i i个值的目前的值根据赋值关系与 x i x_i xi的初始值相反,那么 y i = − i y_i=-i yi=i
如果第 i i i个值赋值为T,那么 y i = ( n + 1 ) y_i=(n+1) yi=(n+1),因为T的反面是F,所以F的表示为 y i = − ( n + 1 ) y_i=-(n+1) yi=(n+1)
如果第 i i i个值赋值为U,那么 y i = 0 y_i=0 yi=0,这样正好满足了 ¬ U = U ¬U=U ¬U=U的性质。

赋值

那赋值就简单了。
x i = x j    ⟺    y i = y j x_i = x_j \iff y_i=y_j xi=xjyi=yj
x i = ¬ x j    ⟺    y i = − y j x_i =¬ x_j \iff y_i=-y_j xi=¬xjyi=yj
x i = T    ⟺    y i = ( n + 1 ) x_i = T \iff y_i=(n+1) xi=Tyi=(n+1)
x i = F    ⟺    y i = − ( n + 1 ) x_i = F \iff y_i=-(n+1) xi=Fyi=(n+1)
x i = U    ⟺    y i = 0 x_i = U \iff y_i=0 xi=Uyi=0

初始化

最后别忘了初始化。
一开始的时候, i i i的值就是 x i x_i xi,所以 y i = i y_i=i yi=i
整个过程实现的代码等到后面说完一起给。

第二部分

逐个考虑

我们现在可以考虑初始值了。假设第 i i i个值的最终值为 a i a_i ai
如果 y i = l y_i=l yi=l ( 1 ≤ ∣ l ∣ ≤ n ) (1 \le |l| \le n) (1ln),我们称为 i i i指向 l l l
先来热个身,我们来看看简单一点的情况。
如果 y i y_i yi=0,那么第 i i i个值是 U U U,所以 x i = U x_i=U xi=U
而T和F是同理的。
我们再来看看稍微难一点的情况。
如果 x i x_i xi已经能确定是U,而存在 q q q满足 y q = i y_q=i yq=i,那么 a q = x i = U a_q=x_i=U aq=xi=U
所以 x q = U x_q=U xq=U了,对吧
T,F的情况也差不多,只不过T和F在取反的时候和U有一定差别
但实际上,我要给出一个思想,就是T和F只要不矛盾,可以理解为同一个值。也就是说T和F抵得上U的范围,因此我们可以把T和F在一起理解为一个和U范围一样的值。
我们再来看一个稍难的情况
m m m个值的关系正好围成了环,即 a r 1 = ∣ x r 2 ∣ , a r 2 = ∣ x r 3 ∣ , … … , a r m = ∣ x r 1 ∣ a_{r1}=|x_{r2}|,a_{r2}=|x_{r3}|,……,a_{rm}=|x_{r1}| ar1=xr2ar2=xr3……arm=xr1
这个时候我们可以直接判断这个环推出的是 a r 1 = ¬ a r 1 a_{r1}=¬a_{r1} ar1=¬ar1还是 a r 1 = a r 1 a_{r1}=a_{r1} ar1=ar1
如果是前者,那么这个 a r 1 = U a_{r1}=U ar1=U,而整个环上的值都只能是 U U U了。
如果是后者,那么并不矛盾,整个环上的值都可以是T或F。
最难的情况就是还有别的值指向了这个环,当然它已经难不了多少了。
如果这个环上都是U,那么指向的值也只能是U。
否则,指向的值就可以是T或F。
初步分析

那么怎么实现呢?当然是并查集!

并查集实现判断

有没有发现其实我们只需要标记必须是 U U U的节点就好了?
其实还能更少。
如果 p p p指向 q q q,那么按照并查集我们可以让 f a q = p fa_q=p faq=p
如果 p , q p,q p,q已经是一组的了,我们就判断他们之间矛不矛盾,矛盾就标记为 U U U,并上传给“队长”。
发现了吧,我们还需要维护当前结点与“队长”的值是相等还是相反,而这和我在并查集中所说的银河英雄传说那道题是一样的。

题目代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
using namespace std;
int c,t,n,m;
int f[100010],ans;//f就是题解中的y 
int g[100010],fa[100010];//g维护的是当前节点是否可以不是U 
bool p[100010];//p维护的是当前节点与“队长”的值是否相等 
int find(int x){
	if(fa[x]==x) return x;
	int qaq=find(fa[x]);//这里是为了先求出p[fa[x]] 
	p[x]^=p[fa[x]];
	return fa[x]=qaq;
}
void unite(int x,int y){
	fa[x]=y;
}
bool same(int x,int y){
	return find(x)==find(y);
}
int main(){
	cin>>c>>t;
	for(int ca=1;ca<=t;ca++){
		cin>>n>>m;
		ans=0;
		for(int i=1;i<=n;i++){
			f[i]=i;
			g[i]=-1;
			fa[i]=i;
			p[i]=0;
		}
		for(int i=1;i<=m;i++){
			char ch;
			int x,y;
			cin>>ch;
			if(ch=='+'){
				cin>>x>>y;
				f[x]=f[y];
			}if(ch=='-'){
				cin>>x>>y;
				f[x]=-f[y];
			}if(ch=='T'){
				cin>>x;
				f[x]=n+1;
			}if(ch=='F'){
				cin>>x;
				f[x]=-(n+1);
			}if(ch=='U'){
				cin>>x;
				f[x]=0;
			}
		}
		for(int i=1;i<=n;i++){
			if(f[i]==0) g[i]=0;
			if(f[i]==(n+1)||f[i]==-(n+1)) g[i]=1;
			if(f[i]==i) g[i]=1;
			if(f[i]==-i) g[i]=0;
		}
		for(int i=1;i<=n;i++){
			if(g[i]==-1){
				int e=abs(f[i]);
				if(!same(i,e)){
					unite(i,e);
					p[i]=(f[i]<0);
				}else{
					if(p[e]!=(f[i]<0)) g[i]=0;
					//注意并查集中的队长一定是没有祖先的,所以一旦有重复,一定是队长 
				}
			}
		}
		for(int i=1;i<=n;i++){
			if(g[find(i)]==0) g[i]=0;
			//如果一个集合的“队长”必须是U,那么整个集合都必须是U 
		}
		for(int i=1;i<=n;i++){
			if(g[i]==0) ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值