2—SAT问题

现有一个由N个布尔值组成的序列A,给出一些限制关系,比如A[x] AND A[y]=0、A[x] OR A[y] OR A[z]=1、A[x] XOR A[y]=0等,要确定A[0..N-1]的值,使得其满足所有限制关系。这个称为SAT问题,特别的,若每种限制关系中最多只对两个元素进行限制,则称为2-SAT问题。

对于x、y有11种关系,将其拆点2x(假),2x+1(真).对于x为假或者y为假这样的条件,我们连两条有向边2x+1->2y、2y+1->2x,注意这里是有向边以及边的起点和终点的关系要确定。同理,我们可以将很多关系都确定,建立一个有向图,进行深搜,可以O(nm)得到解。

 

hdu3622bomb

题目大意:有n对点,每对点中选择一个,最后确定一个实数r,以选出的每一个点做圆心,r做半径,保证圆不相交,求最大的r。

思路:这里的一对点就相当于上面拆出来的点。我们二分答案进行求解,就用2sat问题进行可行性判断,对于距离<二分答案的点相应的连边(注意有向边这一要求)。

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

#define maxnode 1010

#define sta 1000

using namespace std;

double xi[maxnode],yi[maxnode];

int dis[maxnode][maxnode]={0},s[maxnode]={0},stot=0,n,point[maxnode]={0},next[maxnode*maxnode*2]={0},

    en[maxnode*maxnode*2]={0},tot=0;

bool visit[maxnode]={false};

void add(int u,int v)

{

    ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;

}

void pre(int mid)

{

    int i,j;

    memset(point,0,sizeof(point));tot=0;

    for (i=0;i<n;++i)

      for (j=i+1;j<n;++j)

      {

           if (dis[i<<1][j<<1]<mid){add(i<<1,j<<1|1);add(j<<1,i<<1|1);}

           if (dis[i<<1][j<<1|1]<mid) {add(i<<1,j<<1);add(j<<1|1,i<<1|1);}

           if (dis[i<<1|1][j<<1]<mid) {add(j<<1,i<<1);add(i<<1|1,j<<1|1);}

           if (dis[i<<1|1][j<<1|1]<mid) {add(i<<1|1,j<<1);add(j<<1|1,i<<1);}

      }

}

bool dfs(int x)

{

    int i;

    if (visit[x^1]) return false;

    if (visit[x]) return true;

    visit[x]=true;s[++stot]=x;

    for (i=point[x];i;i=next[i])

        if (!dfs(en[i])) return false;

    return true;

}

bool judge(int mid)

{

    int i,j,sum=0;

    pre(mid);memset(visit,false,sizeof(visit));

    for (i=0;i<n*2;i+=2)

    {

        if (!visit[i]&&!visit[i+1])

        {

            stot=0;

            if (!dfs(i))

            {

                while(stot) 

                {

                  visit[s[stot]]=false;--stot;

                }

                if (!dfs(i+1)) return false;

            }

        }

    }

    return true;

}

int main()

{

    freopen("bomb.in","r",stdin);

    freopen("bomb.out","w",stdout);

    

    int m,i,j,l,r,mid;

    scanf("%d",&n);

    for (i=0;i<n;++i)

    {

        scanf("%lf%lf%lf%lf",&xi[i*2],&yi[i*2],&xi[i*2+1],&yi[i*2+1]);

    }

    for (i=0;i<2*n;++i)

      for (j=0;j<2*n;++j)

            dis[i][j]=(int)(sqrt((xi[i]-xi[j])*(xi[i]-xi[j])+(yi[i]-yi[j])*(yi[i]-yi[j]))*sta);

    l=0;r=40000*sta;

    while(l<r)

    {

        mid=(r+l)/2;

        if (judge(mid)) l=mid+1;

        else r=mid;

    }

    printf("%.2f\n",(double)l/(double)(sta*2));

    

    fclose(stdin);

    fclose(stdout);

}
View Code

 

你可能感兴趣的:(问题)