2-SAT——1.0(hdu3062,poj3678)

2-SAT 问题是什么意思,如何求解,大家可以参考 伍昱 的《由对称性解2-SAT问 题》,以及 赵爽 的《2-SAT 解法浅析》两篇论文,很详细,很给力。

hdu3062 Party,裸2-SAT模型,图基本上给好了,判断一下就好。

用 tarjan 算法求强连通,然后判断 b 和 b' 是否在同一个连通分量里面就好。

#include<cstdio>
#include<cstring>
#include<stack>
#include<climits>
using namespace std;

const int N = 2010;
struct Edge{
    int s,e,next;
}edge[1000010];

int n,e_num,vis_num,cnt,head[N],instack[N],low[N],tim[N],belong[N];

void AddEdge(int a,int b){
    edge[e_num].s=a; edge[e_num].e=b;
    edge[e_num].next=head[a]; head[a]=e_num++;
}

void getmap()
{
    int m,a,b,c,d;
    scanf("%d",&m);
    e_num=0;
    memset(head,-1,sizeof(head));
    while(m--){
        scanf("%d%d%d%d",&a,&b,&c,&d);
        AddEdge(2*a+c,2*b+(1-d));
        AddEdge(2*b+d,2*a+(1-c));
    }
}

stack <int>st;
void tarjan(int x){
    int i;
    tim[x]=low[x]=++vis_num;
    instack[x]=1;
    st.push(x);
    for(i=head[x];i!=-1;i=edge[i].next){
        int u=edge[i].e;
        if(tim[u]==-1){
            tarjan(u);
            if(low[x]>low[u])low[x]=low[u];
        }
        else if(instack[u] && low[x]>tim[u])low[x]=tim[u];
    }
    if(low[x]==tim[x]){
        cnt++;
        do{
            i=st.top();
            st.pop();
            instack[i]=0;
            belong[i]=cnt;
        }while(i!=x);
    }
}

void solve(){
    int i;
    vis_num=cnt=0;
    memset(instack,0,sizeof(instack));
    memset(belong,-1,sizeof(belong));
    memset(tim,-1,sizeof(tim));
    memset(low,0,sizeof(low));
    for(i=0;i<2*n;i++){
        if(tim[i]==-1)tarjan(i);
    }

    int flag=1;
    for(i=0;i<n;i++){
        if(belong[2*i]==belong[2*i+1]){
            flag=0;break;
        }
    }
    printf(flag?"YES\n":"NO\n");
}

int main()
{
    while(~scanf("%d",&n))
    {
        getmap();
        solve();
    }
    return 0;
}

poj3678 Katu Puzzle,题意是说给出一些变量,他们可以取 0 或 1 ,然后给出一组他们的由 与,或,异或 三种运算组成的式子,问是否有一组可行解,满足这些式子,也是很裸的2-SAT模型,不解释。

#include<cstdio>
#include<cstring>
#include<stack>
#include<climits>
using namespace std;

const int N = 2010;

struct Edge{
	int s,e,next;
}edge[N*N];

int n,m,e_num,vis_num,cnt,head[N],instack[N],low[N],tim[N],belong[N];

void AddEdge(int a,int b){
	edge[e_num].s=a; edge[e_num].e=b; edge[e_num].next=head[a]; head[a]=e_num++;
}

void getmap()
{
	int i,a,b,c;
	char ch[3];
	e_num=0;
	memset(head,-1,sizeof(head));
	for(i=0;i<m;i++){
		scanf("%d%d%d%s",&a,&b,&c,ch);
		if(ch[0]=='A'){
			if(c==1){
				AddEdge(2*a,2*b+1);
				AddEdge(2*a,2*b);
				AddEdge(2*a+1,2*b+1);

				AddEdge(2*b,2*a+1);
				AddEdge(2*b,2*a);
				AddEdge(2*b+1,2*a+1);
			}
			else{
				AddEdge(2*a+1,2*b);
				AddEdge(2*b+1,2*a);
			}
		}
		else if(ch[0]=='O'){
			if(c==1){
				AddEdge(2*a,2*b+1);
				AddEdge(2*b,2*a+1);
			}
			else{
				AddEdge(2*a,2*b);
				AddEdge(2*a+1,2*b+1);
				AddEdge(2*a+1,2*b);

				AddEdge(2*b,2*a);
				AddEdge(2*b+1,2*a+1);
				AddEdge(2*b+1,2*a);
			}
		}
		else {
			if(c==1){
				AddEdge(2*a,2*b+1);
				AddEdge(2*a+1,2*b);

				AddEdge(2*b,2*a+1);
				AddEdge(2*b+1,2*a);
			}
			else{
				AddEdge(2*a,2*b);
				AddEdge(2*a+1,2*b+1);

				AddEdge(2*b,2*a);
				AddEdge(2*b+1,2*a+1);
			}
		}
	}
}

stack <int>st;
void tarjan(int x){
	int i;
	tim[x]=low[x]=++vis_num;
	instack[x]=1;
	st.push(x);
	for(i=head[x];i!=-1;i=edge[i].next){
		int u=edge[i].e;
		if(tim[u]==-1){
			tarjan(u);
			if(low[x]>low[u])low[x]=low[u];
		}
		else if(instack[u] && low[x]>tim[u])low[x]=tim[u];
	}
	if(low[x]==tim[x]){
		cnt++;
		do{
			i=st.top();
			st.pop();
			instack[i]=0;
			belong[i]=cnt;
		}while(i!=x);
	}
}

void solve(){
	int i;
	vis_num=cnt=0;
	memset(instack,0,sizeof(instack));
	memset(belong,-1,sizeof(belong));
	memset(tim,-1,sizeof(tim));
	memset(low,0,sizeof(low));
	for(i=0;i<2*n;i++){
		if(tim[i]==-1)tarjan(i);
	}
	int flag=1;
	for(i=0;i<n;i++){
		if(belong[2*i]==belong[2*i+1]){
			flag=0;break;
		}
	}
	printf(flag?"YES\n":"NO\n");
}

int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		getmap();
		solve();
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值