2-SAT 问题(洛谷-P4782)
生活随笔
收集整理的這篇文章主要介紹了
2-SAT 问题(洛谷-P4782)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
題目描述
有n個布爾變量x1~xn,另有m個需要滿足的條件,每個條件的形式都是“xi為true/false或xj為true/false”。比如“x1為真或x3為假”、“x7為假或x2為假”。2-SAT 問題的目標是給每個變量賦值使得所有條件得到滿足。
輸入輸出格式
輸入格式:
第一行兩個整數(shù)n和m,意義如體面所述。
接下來m行每行4個整數(shù) i a j b,表示“xi為a或xj為b”(a,b∈{0,1})
輸出格式:
如無解,輸出“IMPOSSIBLE”(不帶引號); 否則輸出"POSSIBLE"(不帶引號),下 一行n個整數(shù)x1~xn(xi∈{0,1}),表示構造出的解。
輸入輸出樣例
輸入樣例#1:
3 1
1 1 3 0
輸出樣例#1:
POSSIBLE
0 0 0
思路:2-SAT問題模版題
源代碼
#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<utility> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #include<bitset> #define EnewPosstr 1e-9 #define newPosI acos(-1.0) #define INF 0x3f3f3f3f #define LL long long const int MOD = 1E9+7; const int N = 2000000+5; const int dx[] = {-1,1,0,0,-1,-1,1,1}; const int dy[] = {0,0,-1,1,-1,1,-1,1}; using namespace std;struct Edge{int to,next; }edge[N*2]; int head[N],tot; int n,m; int dfn[N],low[N]; bool vis[N];//標記數(shù)組 int scc[N];//記錄結點i屬于哪個強連通分量 int block_cnt;//時間戳 int sig;//記錄強連通分量個數(shù) stack<int> S; void init(){tot=0;sig=0;block_cnt=0;memset(head,-1,sizeof(head));memset(vis,0,sizeof(vis));memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(scc,0,sizeof(scc)); } void addEdge(int from,int to){edge[++tot].to=to;edge[tot].next=head[from];head[from]=tot; } void Tarjan(int x) {vis[x]=true;dfn[x]=low[x]=++block_cnt;//每找到一個新點,紀錄當前節(jié)點的時間戳S.push(x);//當前結點入棧for(int i=head[x]; i!=-1; i=edge[i].next) { //遍歷整個棧int y=edge[i].to;//當前結點的下一結點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]) { //滿足強連通分量要求sig++;//記錄強連通分量個數(shù)while(true) { //記錄元素屬于第幾個強連通分量int temp=S.top();S.pop();vis[temp]=false;scc[temp]=sig;if(temp==x)break;}} } bool twoSAT(){for(int i=1;i<=2*n;i++)//找強連通分量if(!dfn[i])Tarjan(i);for(int i=1;i<=n;i++)if(scc[i]==scc[i+n])//條件a與!a屬于同一連通分量,無解return false;return true; } int main() {init();scanf("%d%d",&n,&m);while(m--) {int x,y,xVal,yVal;scanf("%d%d%d%d",&x,&xVal,&y,&yVal);if(xVal==0&&yVal==0){//x為0或y為0addEdge(x+n,y);//x為0,y為1addEdge(y+n,x);//y為0,x為1}else if(xVal==0&&yVal==1){//x為0或y為1addEdge(x+n,y+n);//x為0,y為0addEdge(y,x);//y為1,x為1}else if(xVal==1&&yVal==0){//x為1或y為0addEdge(x,y);//x為1,y為1addEdge(y+n,x+n);//y為0,x為0}else if(xVal==1&&yVal==1){//x為1或y為1addEdge(x,y+n);//x為1,y為0addEdge(y,x+n);//y為1,x為0}}bool flag=twoSAT();if(!flag)printf("IMPOSSIBLE\n");else{printf("POSSIBLE\n");for(int i=1;i<=n;i++){if(scc[i]>scc[i+n])printf("1 ");elseprintf("0 ");}printf("\n");}return 0; }?
總結
以上是生活随笔為你收集整理的2-SAT 问题(洛谷-P4782)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Sigma Function(Light
- 下一篇: 理论基础 —— 图