现有一个由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-10-08 02:19:32