POJ 3678 2-SAT 第一题

18 篇文章 0 订阅
1 篇文章 0 订阅

题意,给一些点,和边的值,和一些运算。

两个点经过运算是否可以满足边的值

比如 i-j 值是1 运算是 AND,那么  点i点j的值只能都是1.

就是求是否所有的点都满足这种情况。

典型的2-SAT问题。

将点s代表0,则s+n代表1。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#include <map>
#include <iomanip>
#define PI acos(-1.0)
#define Max 1005
#define inf 1<<28
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
using namespace std;

struct kdq
{
    int v,next;
} edge[1000005];

int head[Max];
int num=0;
int cntnum=0;
int dfn[Max],belong[Max],low[Max],instack[Max],sta[Max],index,top;

void add(int v,int to)
{
    edge[num].v=to;
    edge[num].next=head[v];
    head[v]=num++;
}

void init()
{
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    num=0;
    cntnum=0;
    index=0;
    top=0;
}
int n,m;

void tarjan(int id)
{
    dfn[id]=low[id]=index++;
    instack[id]=1;
    sta[top++]=id;
    int temp=head[id];
    while(temp!=-1)
    {
        int v=edge[temp].v;
        if(!dfn[v])
        {
            tarjan(v);
            if(low[v]<low[id])low[id]=low[v];
        }
        else if(instack[v]&&dfn[v]<low[id])
        low[id]=dfn[v];
        temp=edge[temp].next;
    }
    if(dfn[id]==low[id])
    {
        do
        {
            temp=sta[--top];
            instack[temp]=0;
            belong[temp]=cntnum;
        }
        while(temp!=id);
        cntnum++;
    }
}
int main()
{

    cin>>n>>m;
    init();
    int s,t,c;
    string op;
    while(m--)
    {
        scanf("%d%d%d",&s,&t,&c);
        cin>>op;
        if(op=="AND")
        {
            if(c)//两个1
            {
                add(s+n,t+n);//1和1连接
                add(t+n,s+n);
                add(s,s+n);//表示只取后者
                add(t,t+n);
            }
            else
            {
                add(s+n,t);//1和0
                add(t+n,s);
            }
        }
        else if(op=="OR")
        {
            if(!c)
            {
                add(s,t);//都是0
                add(t,s);
                add(s+n,s);//表示只取后者
                add(t+n,t);
            }
            else
            {
                add(s,t+n);//0,1
                add(t,s+n);
            }
        }
        else
        {
            if(c)
            {
                add(s,t+n);//一个为0另一个必定为1
                add(s+n,t);
                add(t+n,s);
                add(t,s+n);
            }
            else
            {
                add(s+n,t+n);//一个为0另一个必定为0,一个为1另一个必定为1
                add(t+n,s+n);
                add(s,t);
                add(t,s);
            }
        }
    }
    for(int i=0; i<2*n; i++)
        if(!dfn[i])tarjan(i);
    bool flag=0;
    for(int i=0; i<n; i++)
        if(belong[i]==belong[i+n])
        {
            flag=1;
            break;
        }
    if(flag)cout<<"NO"<<endl;
    else cout<<"YES"<<endl;
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值