Introduction \raisebox{-15pt}{\Large\texttt{Introduction}} Introduction
2-SAT 是用来解决多个类似 A为 true/false 或者 B 为 true/false 的约束之类的问题。
比如说有两个约束:A=true 或 B=false
和 B=true 或 C=true
,此时就可以这样:A=true,B=true,C=true
。
Before
you
read
\raisebox{-15pt}{\Large\texttt{Before you read}}
Before you read
在看懂这篇文章之前,你需要学会
Tarjan
\texttt{Tarjan}
Tarjan 。
Solution
\raisebox{-15pt}{\Large\texttt{Solution}}
Solution
首先,对于一个约束,例如 A=true 或 B=false
,要让他满足条件,那么 A 不满足条件时 B 一定满足条件,B 不满足条件时 A 一定满足条件 。例如 A=false
的时候 B=false
, B=true
的时候 A=true
。
那么我们可以根据这两个条件来进行建边。为方便表示,定义
A
f
A_f
Af 表示 A=false
,
A
t
A_t
At 表示 A=true
。根据上面的条件,可以建
A
f
→
B
f
A_f\to B_f
Af→Bf 和
B
t
→
A
t
B_t\to A_t
Bt→At 这两条边。
现在我们建出了一个图,我们知道,强连通分量中的点是可以互相到达的。也就是说,这里面的一个点满足条件,这个强连通分量里的点也一定满足条件 。于是我们知道,如果有一个变量 A A A, A t A_t At 和 A f A_f Af 在同一个强连通分量里面,则无解。所以在这个图上面跑一遍 Tarjan \texttt{Tarjan} Tarjan 即可。
现在判完了无解,我们考虑如何输出。
其实在
Tarjan
\texttt{Tarjan}
Tarjan 的过程中,已经标好了连通块的顺序,我们只需要看哪个排在前面,就输出哪个就行了。但是注意,
Tarjan
\texttt{Tarjan}
Tarjan 跑出来的拓扑序时倒序,所以在判断时输出的是编号较大的那一个答案。
Code
\raisebox{-15pt}{\Large\texttt{Code}}
Code
【实现细节】
1.
1.
1. 注意建边有没有建错。
2.
2.
2. 输出答案比较时符号要对。
3.
3.
3. 确保你的
Tarjan
\texttt{Tarjan}
Tarjan 是对的。
4.
4.
4. 数组要开双倍。
#include <bits/stdc++.h>
using namespace std;
const int N=2000010;
vector<int> road[N];
stack<int> st;
int dfs[N],conn[N];
int belong[N];
int state[N];
int tot,blk;
int n,m;
void tarjan(int root)
{
dfs[root]=conn[root]=++tot;
st.push(root);
state[root]=1;
for(int i=0; i<road[root].size(); i++)
{
int temp=road[root][i];
if(!dfs[temp])
tarjan(temp),conn[root]=min(conn[root],conn[temp]);
if(state[temp])
conn[root]=min(conn[root],dfs[temp]);
}
if(dfs[root]==conn[root])
{
blk++;
while(st.top()!=root)
{
belong[st.top()]=blk;
state[st.top()]=0;
st.pop();
}
belong[root]=blk;
state[root]=0;
st.pop();
}
return;
}
void work()
{
/* Code */
cin>>n>>m;
for(int i=1; i<=m; i++)
{
int x,y,z,alpha;
cin>>x>>y>>z>>alpha;
road[x+n*(1-y)].push_back(z+n*alpha);
road[z+n*(1-alpha)].push_back(x+n*y);
}
for(int i=1; i<=2*n; i++)
if(!dfs[i])
tarjan(i);
for(int i=1; i<=n; i++)
if(belong[i]==belong[i+n])
{
cout<<"IMPOSSIBLE"<<'\n';
return;
}
cout<<"POSSIBLE"<<'\n';
for(int i=1; i<=n; i++)
cout<<(belong[i]>belong[i+n])<<' ';
cout<<'\n';
return;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
t=1;
while(t--)
work();
return 0;
}