2 − S A T 2-SAT 2−SAT
类似题目
有 n n n个布尔变量,然后有一些约束条件:第 i i i个必须为真(假)或第 j j j个必须为真(假)。
解法
我们将这个关系建成一个图。
首先将第
i
i
i个点拆成
0
/
1
0/1
0/1状态,表示真或假。
如果选了
i
i
i必须得选
j
j
j时,那么连一条单向边
i
i
i到
j
j
j。
但如果选了
i
i
i有很多可以选的话,就都不用连边。
自己可以画图试一试。
接着我们建了这个图。
如果有冲突,显然就是有环。
所以用
t
a
r
j
a
n
tarjan
tarjan判环即可。
代码
#include<bits/stdc++.h>
#define N 4000005
using namespace std;
int n,m,to[N],la[N],ne[N],dfn[N],low[N],vis[N],col[N],sta[N],top,cnt,tot,sum;
void tarjan(int x){
dfn[x]=low[x]=++tot;
vis[x]=1;
sta[++top]=x;
for(int i=la[x];i;i=ne[i]){
int y=to[i];
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
else{
if(vis[y]) low[x]=min(low[x],dfn[y]);
}
}
if(dfn[x]==low[x]){
int y=0;
sum++;
while(y^x){
y=sta[top--];
vis[y]=0;
col[y]=sum;
}
}
}
void add(int u,int v){
to[++cnt]=v;
ne[cnt]=la[u];
la[u]=cnt;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int p1,x1,p2,x2;
scanf("%d%d%d%d",&p1,&x1,&p2,&x2);
if(x1==0&&x2==0){
add(p1+n,p2);
add(p2+n,p1);
}
if(x1==0&&x2==1){
add(p1+n,p2+n);
add(p2,p1);
}
if(x1==1&&x2==0){
add(p2+n,p1+n);
add(p1,p2);
}
if(x1==1&&x2==1){
add(p1,p2+n);
add(p2,p1+n);
}
}
for(int i=1;i<=(n<<1);i++)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;i++)
if(col[i]==col[i+n]){
printf("IMPOSSIBLE");
return 0;
}
printf("POSSIBLE\n");
for(int i=1;i<=n;i++)
if(col[i]>col[i+n]) printf("1 ");
else printf("0 ");
}
其它题目
题目描述
如
解题方法
枚举第一瓣的陌生度,二分枚举第二瓣的陌生度(假设第一瓣一定大于等于第二瓣),然后用
2
−
S
A
T
2-SAT
2−SAT判断一下。
这样可以40分。
然后考虑优化。
我们用并查集从大到小见图,然后判断环。
情况1
如果这是一个图的偶环,那么最短边不可能与答案有关,舍去。
情况2
如果这是一个图的奇环,那么最短边是最第一瓣陌生度的下界,也就是说,第一瓣的陌生度一定大于等于这条边,所以只要看大于等于它的边。
这就是优化,可以做到
O
(
n
3
log
2
n
)
O(n^3\log_2^n)
O(n3log2n)。
听说好可以做到
O
(
n
3
)
O(n^3)
O(n3),不知道。