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);
}

时间: 2024-12-15 01:50:21

2—SAT问题的相关文章

LA 3211 飞机调度(2—SAT)

https://vjudge.net/problem/UVALive-3211 题意: 有n架飞机需要着陆,每架飞机都可以选择“早着陆”和“晚着陆”两种方式之一,且必须选择一种,第i架飞机的早着陆时间为E,晚着陆时间为L,不得在其他时间着陆.你的任务是为这些飞机安排着陆方式,使得整个着陆计划尽量安全.换句话说,如果把所有飞机的实际着陆时间按照从早到晚的顺序排列,相邻两个着陆时间间隔的最小值. 思路: 二分查找最大值P,每次都用2—SAT判断是否可行. 1 #include<iostream>

8.3吝啬SAT问题

吝啬SAT问题是这样的:给定一组子句(每个子句都是其中文字的析取)和整数k,求一个最多有k个变量为true的满足赋值--如果该赋值存在.证明吝啬SAT是NP-完全问题. 1.易知吝啬SAT的解可以在多项式时间内验证,因此属于NP问题. 2.如果我们把吝啬SAT问题中的k设置为输入的数目,那么SAT问题就可以规约到吝啬SAT问题,所以吝啬SAT问题是np-完全问题.

POJ 3207 Ikki&#39;s Story IV - Panda&#39;s Trick(2 - sat啊)

题目链接:http://poj.org/problem?id=3207 Description liympanda, one of Ikki's friend, likes playing games with Ikki. Today after minesweeping with Ikki and winning so many times, he is tired of such easy games and wants to play another game with Ikki. liy

多边形碰撞 -- SAT方法

检测凸多边形碰撞的一种简单的方法是SAT(Separating Axis Theorem),即分离轴定理. 原理:将多边形投影到一条向量上,看这两个多边形的投影是否重叠.如果不重叠,则认为这两个多边形是分离的,否则找下一条向量来继续投影.我们不需要比较很多条向量,因为已经在数学上证明,多边形每条边的垂直向量就是我们需要的向量. 1.AABB 让我们首先以AABB开始(AABB是一种两边分别平行于X-Y轴的矩形) 判断两个AABB是否碰撞,我们只需要投影两次,分别是投影在平行于X轴和Y轴的向量上

hdu 4751 Divide Groups 2—sat问题 还是未理解

Divide Groups Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1443    Accepted Submission(s): 512 Problem Description This year is the 60th anniversary of NJUST, and to make the celebration mor

HIT 1917 2—SAT

题目大意:一国有n个党派,每个党派在议会中都有2个代表, 现要组建和平委员会,要从每个党派在议会的代表中选出1人,一共n人组成和平委员会. 已知有一些代表之间存在仇恨,也就是说他们不能同时被选为和平委员会的成员, 现要你判断满足要求的和平委员会能否创立?如果能,请任意给出一种方案.( POI 0106 ) ----------------------------------------- 这道题就是裸的2-SAT 不过我用了tarjan缩点 然后一波拓排 tips:一个问题无解当且仅当一个集合的

SAT考试里最难的数学题? &middot; 三只猫的温暖

问题 今天无意中在Quora上看到有人贴出来一道号称是SAT里最难的一道数学题,一下子勾起了我的兴趣.于是拿起笔来写写画画,花了差不多十五分钟搞定.觉得有点意思,决定把解题过程记下来.原帖的图太小,我用GeoGebra重新画了一遍.没错,我就是强迫症. 为了省事,就把这道题叫做RASBTC. In the figure above, arc (text{SBT}) is one quarter of a circle with center (text{R}) and radius 6. If

SAT求解器变元活跃度计算模式的切换

变元活跃度计算模式有:VSIDS.基于历史出现时刻与当前冲突时刻距离等 有三个最小堆: // A priority queue of variables ordered with respect to the variable activity. Heap<VarOrderLt> order_heap_CHB,                                order_heap_VSIDS, order_heap_distance; 一般的求解切换方式是: conflicts

SAT求解器快速入门

从事组合优化或信息安全方向的研究人员,基于SMT研究,需要快速学习SAT求解器的基本原理和方法.以下是快速入门的几点体会: 1.理清需要——是完备求解器还是不完备求解器 完备求解器 能给出SAT.UNSAT.unknow三种确定的答案,尤其是UNSAT结论能给出证明推导过程,指出导致矛盾的关键路径.   不完备求解器能给出SAT.unknow两种结论.SAT结论给出一组可满足解即完成求解任务.可能会存在其他一组或多组可满足解.如果问题本身不知一组解,那么不同的求解器得出的可满足解可能不同. 2.