ZOJ 3717 Balloon (2sat+二分)

这题是一个二分半径+判定的题,但是开始不知道怎么去判定,以前听别人提起过sat问题,感觉这题是一个2sat模型,因为有一些限制比如:同一组两个里面只能选一个,两个球重叠时只能选其中的一个等,这很符合2sat的模型,于是去翻了下白书上2sat问题的解法实现,建图后直接用搜索判定,我用这种方法写了写,开始提交wa了几次,wa的原因是:题目说在round之后也要保证不重叠,那就只有舍掉小数点3位以后的数了,后面就ac了,代码如下:

 

#include<stdio.h>
#include<math.h>
#include<string.h>

struct E
{
	int t,next;
}edge[200010];

int ant,head[500];

void add(int a,int b)
{
	edge[ant].t=b;
	edge[ant].next=head[a];
	head[a]=ant++;
}

int vis[500],sta[500],sp,n;
int check(int root)
{
	if(vis[root^1]) return 0;
	if(vis[root]) return 1;
	sta[sp++]=root;
	vis[root]=1; int i;
	for(i=head[root];i!=-1;i=edge[i].next)
		if(check(edge[i].t)==0) return 0;
	return 1;
}

int dfs(void)
{
	int i;
	memset(vis,0,sizeof(vis));
	for(i=1;i<=n;i++)
	{
		if(vis[2*i]||vis[2*i+1]) continue;
		sp=0;
		if(!check(2*i)){
			while(sp>0) vis[sta[--sp]]=0;
			if(!check(2*i+1)) return 0;
		}
	}
	return 1;
}

struct point
{
	double x,y,z;
	point(double a=0,double b=0,double c=0):x(a),y(b),z(c){}
}P[210][2];

double dis(point a,point b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z)); }

double const eps=1e-11;

void init(double d)
{
	int i,j,k,g;
	ant=0;memset(head,-1,sizeof(head));
	for(i=1;i<=n;i++)
	{
		for(j=i+1;j<=n;j++)
		{
			for(k=0;k<2;k++){
				for(g=0;g<2;g++){
					if(dis(P[i][k],P[j][g])<d){
						add(i*2+k,j*2+(g^1));
						add(j*2+g,i*2+(k^1));
					}	
				}
			}
		}
	}
}

int main()
{
	int i;
	double ans,l,r;
	while(scanf("%d",&n)!=EOF)
	{
		for(i=1;i<=n;i++){
			scanf("%lf%lf%lf",&P[i][0].x,&P[i][0].y,&P[i][0].z);
			scanf("%lf%lf%lf",&P[i][1].x,&P[i][1].y,&P[i][1].z);
		}
		l=0;r=dis(point(0,0,0),point(10000,10000,10000));
		while(r-l>1e-4){
			ans=(r+l)/2;
			init(2*ans);
			if(dfs()) l=ans;
			else r=ans;
		}
		printf("%.3lf\n",ans-0.0005);
	}
	return 0;
}


 

你可能感兴趣的:(ZOJ 3717 Balloon (2sat+二分))