POJ2723,2-sat问题,二分查找

入手的第一道2-sat问题,关于怎样建图,迷糊了2天,在网上看到各种各样的解法,感到眼花缭乱,无所适从。
于是乎,直到今天才有了一点眉目。
做2-sat难在怎样建图。到目前为止,由于做的题数目有限,只能说说自己浅薄的见解。
最朴素的2-sat问题的形式是,有n个集合,每个集合中两个元素,0,1,2,…,2*n-1,从每个集合中选出一个元素,并且不同集合之间的元素之间存在某些约束,然后再根据题目求出或者判断是否能够达到某种条件。
由于是{0,1},{2,3},{4,5}…{2n-2,2n-1},所以0的对立点就是1,2的对立点就是3…那么我们在求点i的对立点的时候,就用位运算就可以求出i的对立点i^1了。我们根据题目的约束条件,进行构图。一般有下列约束条件:
A[x]
NOT A[x]
A[x] AND A[y]
A[x] AND NOT A[y]
A[x] OR A[y]
A[x] OR NOT A[y]
NOT (A[x] AND A[y])
NOT (A[x] OR A[y])
A[x] XOR A[y]
NOT (A[x] XOR A[y])
A[x] XOR NOT A[y]
在这道题中,约束条件是X OR Y,则可以建图X’->Y, Y’->X,然后就可以按照套路做了。
代码如下:

/*************************************************************************
	> File Name: main.cpp
	> Author:Eagles 
	> Mail:None 
	> Created Time: 2018年09月21日 星期五 18时27分27秒
	> Description: 
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
#define N 5000
struct mydot
{
    int scc,low,dfn;
    bool is_in;

    void clear()
    {
        scc=low=dfn=-1;
        is_in=false;
    }
}dot[N];
struct node
{
    int to;
    int nex;
}E[N*N];

int head[2*N];
int hash_val[2*N];//将n对关系映射成{0,1},{2,3}之类的
int datam[N][2];

int n,m,cnt,dep,col;
stack<int>s;

void addEdge(int a, int b)
{
    E[cnt].to=b;
    E[cnt].nex=head[a];
    head[a]=cnt++;
}

void init()
{
    memset(head,-1,sizeof(head));
    cnt=dep=col=0;

    while (!s.empty())
        s.pop();
    for (int i=0; i<2*n; i++)
        dot[i].clear();
}

void tarjan(int u)
{
    s.push(u);
    dot[u].is_in=true;
    dot[u].low=dot[u].dfn=++dep;

    for (int i=head[u]; i!=-1; i=E[i].nex)
    {
        int v=E[i].to;

        if (dot[v].dfn==-1)
        {
            tarjan(v);
            dot[u].low=min(dot[u].low,dot[v].low);
        }
        else if (dot[v].is_in)
            dot[u].low=min(dot[v].dfn,dot[u].low);
    }

    if (dot[u].low == dot[u].dfn)
    {
        col++;

        int v=s.top();
        s.pop();

        while (v != u)
        {
            dot[v].is_in=false;
            dot[v].scc=col;
            v=s.top();
            s.pop();
        }

        dot[v].scc=col;
        dot[v].is_in=false;
    }
}

bool check()
{
    for (int i=0; i<2*n; i+=2)
        if (dot[i].scc == dot[i^1].scc)
            return false;

    return true;
}

bool solve(int mid)
{
    init();

    for (int i=0; i<mid; i++)
    {
        int u=hash_val[datam[i][0]];
        int v=hash_val[datam[i][1]];
        //根据约束条件加边
        addEdge(u,v^1);
        addEdge(v,u^1);
    }


    for (int i=0; i<2*n; i++)
        if (dot[i].dfn==-1)
            tarjan(i);

    return check();
}

int main()
{
    while (~scanf("%d%d",&n,&m)&&(m+n))
    {
        for (int i=0; i<2*n; i++)
        {
            int a;
            scanf("%d",&a);
            hash_val[a]=i;//映射
        }

        for (int i=0; i<m; i++)
        {
            scanf("%d%d",&datam[i][0],&datam[i][1]);存储约束条件
        }

        int l,r,mid;
        l=0,r=m;

        while (l+1<r)//二分查找
        {
            mid=(l+r)>>1;

            if (solve(mid))
                l=mid;
            else
                r=mid-1;
        }

        if (solve(r)) l=r;

        printf("%d\n",l);
    }
    return 0;
}

路漫漫其修远兮,吾将上下而求索。

发布了45 篇原创文章 · 获赞 2 · 访问量 3081

猜你喜欢

转载自blog.csdn.net/wysiwygo/article/details/82805961