[模板] 2-SAT 问题

2-sat问题主要解决的是一类二取一的问题.做法就是先建图,然后跑tarjan,然后就判断正负是否冲突,假如有冲突,就说明无解,否则就判断哪个的序号大...话说我也不知道为什么序号大就代表1.

题干:

题目背景

2-SAT 问题 模板
题目描述

有n个布尔变量x1x_1x1​~xnx_nxn​,另有m个需要满足的条件,每个条件的形式都是“xix_ixi​为true/false或xjx_jxj​为true/false”。比如“x1x_1x1​为真或x3x_3x3​为假”、“x7x_7x7​为假或x2x_2x2​为假”。2-SAT 问题的目标是给每个变量赋值使得所有条件得到满足。
输入输出格式
输入格式:
第一行两个整数n和m,意义如体面所述。
接下来m行每行4个整数 i a j b,表示“xix_ixi​为a或xjx_jxj​为b”(a,b∈{0,1})
输出格式:
如无解,输出“IMPOSSIBLE”(不带引号); 否则输出"POSSIBLE"(不带引号),下 一行n个整数x1x_1x1​~xnx_nxn​(xix_ixi​∈{0,1}),表示构造出的解。
输入输出样例
输入样例#1: 复制
3 1
1 1 3 0
输出样例#1: 复制
POSSIBLE
0 0 0
说明
1<=n,m<=1e6 , 前3个点卡小错误,后面5个点卡效率,由于数据随机生成,可能会含有( 10 0 10 0)之类的坑,但按照最常规写法的写的标程没有出错,各个数据点卡什么的提示在标程里。

 

题解:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
#define lv(i,a,n) for(int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
struct node
{
    int l,r,nxt;
}a[4000014];
int lst[2000005],len = 0;
void add(int x,int y)
{
    a[++len].l = x;
    a[len].r = y;
    a[len].nxt = lst[x];
    lst[x] = len;
}
int x,y,z,p,n,m,num = 0,ans = 0,top = 0;
int low[2000005],stk[2000005],dfn[2000005],vis[2000005];
int col[2000005];
void tarjan(int u)
{
    low[u] = dfn[u] = ++num;
    stk[++top] = u;
    vis[u] = 1;
    for(int k = lst[u];k;k = a[k].nxt)
    {
        int y = a[k].r;
        if(!dfn[y])
        {
            tarjan(y);
            low[u] = min(low[u],low[y]);
        }
        else if(vis[y])
        {
            low[u] = min(low[u],dfn[y]);
        }
    }
    if(low[u] == dfn[u])
    {
        ans ++;
        int v;
        do
        {
            v = stk[top--];
            vis[v] = 0;
            col[v] = ans;
        }
        while(u != v);
    }
}
int main()
{
    read(n);read(m);
    int f1,f2;
    duke(i,1,m)
    {
        read(x);read(f1);read(y);read(f2);
        int k1,k2;
        k1 = f1 ^ 1;
        k2 = f2 ^ 1;
        add(x + k1 * n,y + f2 * n);//建边
        add(y + k2 * n,x + f1 * n);
    }
    duke(i,1,2 * n)
        if(!dfn[i])
            tarjan(i);
    int ok = 1;
    duke(i,1,n)
    {
        if(col[i] == col[i + n])
        {
            ok = 0;
            printf("IMPOSSIBLE\n");
            return 0;
        }
    }
    printf("POSSIBLE\n");
    duke(i,1,n)
    {
        printf("%d ",col[i] > col[i + n]);
    }
    printf("\n");
    return 0;
}
/*
3 1
1 1 3 0
*/

 

posted @ 2018-09-21 14:19  DukeLv  阅读(150)  评论(0编辑  收藏  举报