hdu2823 2010.3.6

hdu2823 2010.3.6

The widest road

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 72    Accepted Submission(s): 13

 

 

Problem Description

There were two families in the village —family A and family B, while these two families didn’t get along well with eachother. Now the head of the village decided to make a road through the villageand it must be straight, for a straight line makes the way shortest andmeanwhile, saves the cost. At that time, the heads of the two familiesproposed, because they didn’t want their own families live separated along thetwo sides of the road, thus it might decrease the solidarity of family. Besides,the two families were antipathetic to each other; neither wanted to livetogether with the other in a same side of the road. Then it made the villagehead in a pickle, he hoped the road to be as wide as possible. So what’s thepossible maximal width of this road?

In order to simplify the problem, let’sregard the living place of each family member is just a point.

 

 

 

Input

There are several test cases in the input.

 

The first line of each input contains n andm (1 ≤ m,n ≤ 1000). As for the following n lines, there are two numbers in everyline, representing the living places of A family members. And the following mlines represent the living places of B family members.

 

 

Output

The output numbers of each line are themaximal width of the road (retain four decimal), while if it’s impossible tomake such a road, then just output 0.0000.

 

 

Sample Input

3 3

0.0 0.0

1.0 0.0

0.0 1.0

4.0 0.0

5.0 0.0

4.0 1.0

 

 

Sample Output

3.0000

 

 

Source

2009 Multi-University Training Contest 1 -Host by TJU

 

 

Recommend

gaojie

 

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define eps 1e-8
#define zero(x) (((x)>0?(x):-(x))<eps)
#define _sign(x) ((x)>eps?1:((x)<-eps?2:0))
struct point{double x,y;};

//计算cross product (P1-P0)x(P2-P0)
double xmult(point p1,point p2,point p0){
	return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
//graham算法顺时针构造包含所有共线点的凸包,O(nlogn)
point p1,p2;
int graham_cp(const void* a,const void* b){
	double ret=xmult(*((point*)a),*((point*)b),p1);
	return zero(ret)?(xmult(*((point*)a),*((point*)b),p2)>0?1:-1):(ret>0?1:-1);
}
void _graham(int n,point* p,int& s,point* ch){
	int i,k=0;
	for (p1=p2=p[0],i=1;i<n;p2.x+=p[i].x,p2.y+=p[i].y,i++)
		if (p1.y-p[i].y>eps||(zero(p1.y-p[i].y)&&p1.x>p[i].x))
			p1=p[k=i];
	p2.x/=n,p2.y/=n;
	p[k]=p[0],p[0]=p1;
	qsort(p+1,n-1,sizeof(point),graham_cp);
	for (ch[0]=p[0],ch[1]=p[1],ch[2]=p[2],s=i=3;i<n;ch[s++]=p[i++])
		for (;s>2&&xmult(ch[s-2],p[i],ch[s-1])<-eps;s--);
}

//构造凸包接口函数,传入原始点集大小n,点集p(p原有顺序被打乱!)
//返回凸包大小,凸包的点在convex中
//参数maxsize为1包含共线点,为0不包含共线点,缺省为1
//参数clockwise为1顺时针构造,为0逆时针构造,缺省为1
//在输入仅有若干共线点时算法不稳定,可能有此类情况请另行处理!
//不能去掉点集中重合的点
int graham(int n,point* p,point* convex,int maxsize=1,int dir=1){
	point* temp=new point[n];
	int s,i;
	_graham(n,p,s,temp);
	for (convex[0]=temp[0],n=1,i=(dir?1:(s-1));dir?(i<s):i;i+=(dir?1:-1))
		if (maxsize||!zero(xmult(temp[i-1],temp[i],temp[(i+1)%s])))
			convex[n++]=temp[i];
	delete []temp;
	return n;
}

//两点距离
double distance(point p1,point p2){
	return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}

//点到线段距离
double disptoseg(point p,point l1,point l2){
	point t=p;
	t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;
	if (xmult(l1,t,p)*xmult(l2,t,p)>eps)
		return distance(p,l1)<distance(p,l2)?distance(p,l1):distance(p,l2);
	return fabs(xmult(p,l1,l2))/distance(l1,l2);
}

//判三点共线
int dots_inline(point p1,point p2,point p3){
	return zero(xmult(p1,p2,p3));
}

//判两点在线段同侧,点在线段上返回0
int same_side(point p1,point p2,point l1,point l2){
	return xmult(l1,p1,l2)*xmult(l1,p2,l2)>eps;
}

//判点是否在线段上,包括端点
int dot_online_in(point p,point l1,point l2){
	return zero(xmult(p,l1,l2))&&(l1.x-p.x)*(l2.x-p.x)<eps&&(l1.y-p.y)*(l2.y-p.y)<eps;
}

//判两线段相交,包括端点和部分重合
int intersect_in(point u1,point u2,point v1,point v2){
	if (!dots_inline(u1,u2,v1)||!dots_inline(u1,u2,v2))
		return !same_side(u1,u2,v1,v2)&&!same_side(v1,v2,u1,u2);
	return dot_online_in(u1,v1,v2)||dot_online_in(u2,v1,v2)||dot_online_in(v1,u1,u2)||dot_online_in(v2,u1,u2);
}

//判点在凸多边形内或多边形边上,顶点按顺时针或逆时针给出
int inside_convex(point q,int n,point* p){
	int i,s[3]={1,1,1};
	for (i=0;i<n&&s[1]|s[2];i++)
		s[_sign(xmult(p[(i+1)%n],q,p[i]))]=0;
	return s[1]|s[2];
}

void solve(int a,int b,point ca[],point cb[])
{
	double tmp,ret;

	if(a==1&&b==1){
		printf("%.4lf\n",distance(ca[0],cb[0]));
		return;
	}

	if(a==1&&b==2){
		printf("%.4lf\n",disptoseg(ca[0],cb[0],cb[1]));
		return;
	}

	if(a==2&&b==1){
		printf("%.4lf\n",disptoseg(cb[0],ca[0],ca[1]));
		return;
	}

	if(a==2&&b==2){
		if(intersect_in(ca[0],ca[1],cb[0],cb[1])==1){
			printf("0.0000\n");
			return;
		}
		ret=1000000000;
		tmp=disptoseg(ca[0],cb[0],cb[1]);
		if(tmp<ret)
			ret=tmp;
		tmp=disptoseg(ca[1],cb[0],cb[1]);
		if(tmp<ret)
			ret=tmp;
		tmp=disptoseg(cb[0],ca[0],ca[1]);
		if(tmp<ret)
			ret=tmp;
		tmp=disptoseg(cb[1],ca[0],ca[1]);
		if(tmp<ret)
			ret=tmp;
		printf("%.4lf\n",ret);
		return;
	}

	if(a==1&&b>=3){
		if(inside_convex(ca[0],b,cb)==1){
			printf("0.0000\n");
			return;
		}
		ret=1000000000;
		for(int i=0;i<b-1;i++){
			tmp=disptoseg(ca[0],cb[i],cb[i+1]);
			if(tmp<ret)
				ret=tmp;
		}
		tmp=disptoseg(ca[0],cb[0],cb[b-1]);
		if(tmp<ret)
			ret=tmp;
		printf("%.4lf\n",ret);
		return;
	}

	if(a>=3&&b==1){
		if(inside_convex(cb[0],a,ca)==1){
			printf("0.0000\n");
			return;
		}
		ret=1000000000;
		for(int i=0;i<a-1;i++){
			tmp=disptoseg(cb[0],ca[i],ca[i+1]);
			if(tmp<ret)
				ret=tmp;
		}
		tmp=disptoseg(cb[0],ca[0],ca[a-1]);
		if(tmp<ret)
			ret=tmp;
		printf("%.4lf\n",ret);
		return;
	}

	if(a==2&&b>=3){
		if(inside_convex(ca[0],b,cb)==1||inside_convex(ca[1],b,cb)==1){
			printf("0.0000\n");
			return;
		}

		for(int i=0;i<b-1;i++){
			if(intersect_in(ca[0],ca[1],cb[i],cb[i+1])==1){
				printf("0.0000\n");
				return;
			}
		}
		if(intersect_in(ca[0],ca[1],cb[0],cb[b-1])==1){
			printf("0.0000\n");
			return;
		}
		
		ret=1000000000;
		for(int i=0;i<a;i++){
			for(int j=0;j<b-1;j++){
				tmp=disptoseg(ca[i],cb[j],cb[j+1]);
				if(tmp<ret)
					ret=tmp;
			}
			tmp=disptoseg(ca[i],cb[0],cb[b-1]);
			if(tmp<ret)
				ret=tmp;
		}
		for(int i=0;i<b;i++){
			for(int j=0;j<a-1;j++){
				tmp=disptoseg(cb[i],ca[j],ca[j+1]);
				if(tmp<ret)
					ret=tmp;
			}
			tmp=disptoseg(cb[i],ca[0],ca[a-1]);
			if(tmp<ret)
				ret=tmp;
		}
		printf("%.4lf\n",ret);
		return;
	}

	if(a>=3&&b==2){
		if(inside_convex(cb[0],a,ca)==1||inside_convex(cb[1],a,ca)==1){
			printf("0.0000\n");
			return;
		}

		for(int i=0;i<a-1;i++){
			if(intersect_in(cb[0],cb[1],ca[i],ca[i+1])==1){
				printf("0.0000\n");
				return;
			}
		}
		if(intersect_in(cb[0],cb[1],ca[0],ca[a-1])==1){
			printf("0.0000\n");
			return;
		}
		
		ret=1000000000;
		for(int i=0;i<a;i++){
			for(int j=0;j<b-1;j++){
				tmp=disptoseg(ca[i],cb[j],cb[j+1]);
				if(tmp<ret)
					ret=tmp;
			}
			tmp=disptoseg(ca[i],cb[0],cb[b-1]);
			if(tmp<ret)
				ret=tmp;
		}
		for(int i=0;i<b;i++){
			for(int j=0;j<a-1;j++){
				tmp=disptoseg(cb[i],ca[j],ca[j+1]);
				if(tmp<ret)
					ret=tmp;
			}
			tmp=disptoseg(cb[i],ca[0],ca[a-1]);
			if(tmp<ret)
				ret=tmp;
		}
		printf("%.4lf\n",ret);
		return;
	}
	
	if(a>=3&&b>=3){
		for(int i=0;i<a;i++){
			if(inside_convex(ca[i],b,cb)==1){
				printf("0.0000\n");
				return;
			}
		}
		for(int i=0;i<b;i++){
			if(inside_convex(cb[i],a,ca)==1){
				printf("0.0000\n");
				return;
			}
		}
		
		for(int i=0;i<a-1;i++){
			for(int j=0;j<b-1;j++){
				if(intersect_in(ca[i],ca[i+1],cb[j],cb[j+1])==1){
					printf("0.0000\n");
					return;
				}
			}
			if(intersect_in(ca[i],ca[i+1],cb[0],cb[b-1])==1){
				printf("0.0000\n");
				return;
			}
		}
		for(int i=0;i<b-1;i++){
			if(intersect_in(ca[0],ca[a-1],cb[i],cb[i+1])==1){
				printf("0.0000\n");
				return;
			}
		}
		if(intersect_in(ca[0],ca[a-1],cb[0],cb[b-1])==1){
			printf("0.0000\n");
			return;
		}

		ret=1000000000;
		for(int i=0;i<a;i++){
			for(int j=0;j<b-1;j++){
				tmp=disptoseg(ca[i],cb[j],cb[j+1]);
				if(tmp<ret)
					ret=tmp;
			}
			tmp=disptoseg(ca[i],cb[0],cb[b-1]);
			if(tmp<ret)
				ret=tmp;
		}
		for(int i=0;i<b;i++){
			for(int j=0;j<a-1;j++){
				tmp=disptoseg(cb[i],ca[j],ca[j+1]);
				if(tmp<ret)
					ret=tmp;
			}
			tmp=disptoseg(cb[i],ca[0],ca[b-1]);
			if(tmp<ret)
				ret=tmp;
		}
		printf("%.4lf\n",ret);
		return;
	}
}

int main()
{
	int n,m,a,b;
	point pa[1005],pb[1005],ca[1005],cb[1005];

	while(scanf("%d%d",&n,&m)!=EOF){
		for(int i=0;i<n;i++)
			scanf("%lf%lf",&pa[i].x,&pa[i].y);
		for(int i=0;i<m;i++)
			scanf("%lf%lf",&pb[i].x,&pb[i].y);
		if(n<3){
			for(int i=0;i<n;i++)
				ca[i]=pa[i];
			a=n;
		}
		if(m<3){
			for(int i=0;i<m;i++)
				cb[i]=pb[i];
			b=m;
		}
		if(n>=3){
			a=graham(n,pa,ca,0);
			if(a==1){
				ca[a]=pa[a];
				a++;
			}
		}
		if(m>=3){
			b=graham(m,pb,cb,0);
			if(b==1){
				cb[b]=pb[b];
				b++;
			}
		}
		solve(a,b,ca,cb);
	}

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值