列表

详情


NC243749. Known as the Fruit Brother

描述

English Statement (PDF)
中文题面 (PDF)

输入描述

见 PDF 题面

输出描述

见 PDF 题面

示例1

输入:

1 2 2
0 2 7 4
-3 3
8 2
1 1 6 6

输出:

9.543203767

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++ 11.0.1) 解法, 执行用时: 607ms, 内存消耗: 58680K, 提交时间: 2022-10-02 00:04:32

#include<bits/stdc++.h>
#define int long long
#define MAXN 600001
using namespace std;
int n,m,xs,ys,xt,yt,bia;
double R;
const double eps = 1e-8;
const double pi = acos(-1.0);
int sgn(double x)
{
	if(fabs(x) < eps) return 0;//认为是0 
	if(x < 0) return -1;//负数 
	else return 1;//正数 
}
inline double sqr(double x){return x*x;}
struct Point
{
	double x,y;
	Point(){}
	Point(double X,double Y){x=X;y=Y;}
	void input(){scanf("%lf%lf",&x,&y);}
	void output(){printf("%.2f%.2f",x,y);}
	bool operator==(Point b) const//判断是否相等 
	{return sgn(x-b.x)==0&&sgn(y-b.y)==0;}
	bool operator<(Point b) const
	{return sgn(x-b.x)==0? sgn(y-b.y)<0:x<b.x;}
	Point operator+(const Point &b) const
	{return Point(x+b.x,y+b.y);}//加 
	Point operator-(const Point &b) const
	{return Point(x-b.x,y-b.y);}//减 
	Point operator*(const double &k) const
	{return Point(x*k,y*k);}//乘 
	Point operator/(const double &k) const
	{return Point(x/k,y/k);}//除 
	double operator^(const Point &b) const
	{return x*b.y-y*b.x;}//叉积 
	double operator*(const Point &b) const
	{return x*b.x+y*b.y;}//点积 
	double lenth(){return hypot(x,y);}//返回长度
	double lenth2(){return x*x+y*y;}//返回长度的平方
	double distance(Point p){return hypot(x-p.x,y-p.y);}//两点长度
	Point trunc(double r)//向量长度变为r 
	{
		double l=lenth();
		if(!sgn(l)) return *this;
		r/=l;
		return Point(x*r,y*r);
	}
};
struct Line
{
	Point s,e;
	Line(){}
	Line(Point S,Point E){s=S;e=E;}
	bool operator==(Line v){return (s==v.s)&&(e==v.e);}
	void adjust(){if(e<s)swap(s,e);}
	double length(){return s.distance(e);}//线段长度
	Point crosspoint(Line v)
	{//求两直线的交点
		double a1=(v.e-v.s)^(s-v.s);
		double a2=(v.e-v.s)^(e-v.s);
		return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
	}
	int relation(Point p)//点线关系 
	{//1左侧 2右侧 3线上 
		int c=sgn((p-s)^(e-s));
		if(c<0) return 1;
		else if(c>0) return 2;
		else return 3;
	}
	bool parallel(Line v)
	{//判断两向量平行(对应直线平行或重合)
		return sgn((e-s)^(v.e-v.s))==0;
	}
	int linecrossline(Line v)//两直线关系 
	{//0平行 1重合 2相交 
		if((*this).parallel(v)) return v.relation(s)==3;
		return 2;
	}
	bool ifcrossline(Line v)
	{//判断两线段是否相交 
		if(!(max(s.x,e.x)+eps>=min(v.s.x,v.e.x)&&min(s.x,e.x)<=max(v.s.x,v.e.x)+eps))
			return 0;
		if(!(max(s.y,e.y)+eps>=min(v.s.y,v.e.y)&&min(s.y,e.y)<=max(v.s.y,v.e.y)+eps))
			return 0;
		if(((e-s)^(v.s-s))*((e-s)^(v.e-s))>eps)
			return 0;
		if(((v.e-v.s)^(s-v.s))*((v.e-v.s)^(e-v.s))>eps)
			return 0;
		return 1;
	}
	double dispointtoline(Point p)
	{//点到直线的距离
		return fabs((p-s)^(e-s))/length();
	}
	double dispointtoseg(Point p)
	{//点到线段的距离
		if(sgn((p-s)*(e-s))<0||sgn((p-e)*(s-e))<0)
			return min(p.distance(s),p.distance(e));
		return dispointtoline(p);
	}
	Point lineprog(Point p)
	{//返回点p在直线上的投影
		return s+(((e-s)*((e-s)*(p-s)))/((e-s).lenth2()));
	}
};
struct Circle
{
	Point p;//圆心
	double r;//半径
	Circle(){}
	Circle(Point P,double R){p=P;r=R;}
	Circle(double x,double y,double R){p=Point(x,y);r=R;}
	void input(){p.input();scanf("%lf",&r);}
	void output(){printf("%.2lf %.2lf %.2lf\n",p.x,p.y,r);}
	bool operator==(Circle v)
	{return (p==v.p)&&sgn(r-v.r)==0;}
	bool operator<(Circle v) const
	{return ((p<v.p)||((p==v.p)&&sgn(r-v.r)<0));}
	double area(){return pi*r*r;}//面积
	double circumference(){return 2*pi*r;}//周长
	int relation(Point b)//点和圆的关系
	{//0圆外 1圆上 2圆内 
		double dst=b.distance(p);
		if(sgn(dst-r)<0) return 2;
		else if(sgn(dst-r)==0) return 1;
		return 0;
	}
	int relationseg(Line v)//线段和圆的关系
	{//0圆外 1相切 2圆内 
		double dst=v.dispointtoseg(p);
		if(sgn(dst-r)<0) return 2;
		else if(sgn(dst-r)==0) return 1;
		return 0;
	}
	int relationline(Line v)//直线和圆的关系 
	{//0圆外 1相切 2圆内 
		double dst=v.dispointtoline(p);
		if(sgn(dst-r)<0) return 2;
		else if(sgn(dst-r)==0) return 1;
		return 0;
	}
	int pointcrossline(Line v,Point &p1,Point &p2)
	{//求直线和圆的交点个数 
		if(!(*this).relationline(v)) return 0;
		Point a=v.lineprog(p);
		double d=v.dispointtoline(p);
		d=sqrt(r*r-d*d);
		if(sgn(d)==0){p1=a;p2=a;return 1;}
		p1=a+(v.e-v.s).trunc(d);
		p2=a-(v.e-v.s).trunc(d);
		return 2;
	}
};
struct squ
{
	Point leftdown;
	Point leftup;
	Point rightup;
	Point rightdown;
}a[MAXN];
Point c[MAXN],s,t,sp[MAXN*10];
Line l[MAXN*10];
int head[MAXN*10],cnt,vis[MAXN*10],fa[MAXN*10];
double dis[MAXN];
struct node
{
	int nxt,to;
	double cost;
}e[MAXN*10];
bool check(Point x)
{
	int flag=1;
	for(int i=1;i<=n;i++)
	{
		if(a[i].leftup.x<=x.x&&a[i].leftup.y>=x.y)
		if(a[i].rightup.x>=x.x&&a[i].rightup.y>=x.y)
		if(a[i].rightdown.x>=x.x&&a[i].rightdown.y<=x.y)
		if(a[i].leftdown.x<=x.x&&a[i].leftdown.y<=x.y)
		{
			flag=0;
			break;
		}
	}
	return flag;
}
void insert(int now,int aim,double wealth)
{
	//cout<<"insert:from"<<now<<" to "<<aim<<" cost:"<<wealth<<endl; 
	e[++cnt].nxt=head[now];
	e[cnt].to=aim;
	e[cnt].cost=wealth;
	head[now]=cnt;
}
void dijkstra()
{
	priority_queue<pair<double,int> >q;
	for(int i=1;i<MAXN;i++) dis[i]=1e18;
	memset(vis,0,sizeof(vis));
    dis[0]=0;
    q.push(make_pair(0,0));
	while(!q.empty())
	{
		int u=q.top().second;q.pop();
		if(vis[u]) continue;
		vis[u]=1;
		for(int i=head[u];i;i=e[i].nxt)
		{
			int temp=e[i].to;
			if(dis[temp]>dis[u]+e[i].cost)
			{
				dis[temp]=dis[u]+e[i].cost;
				q.push(make_pair(-dis[temp],temp));
			}
		}
	}
}
Point poly[MAXN]; 
signed main()
{
	scanf("%lld%lld%lf",&n,&m,&R);
	for(int i=1;i<=n;i++)
	{
		a[i].leftdown.input();
		a[i].rightup.input();
		a[i].leftup.x=a[i].leftdown.x;
		a[i].leftup.y=a[i].rightup.y;
		a[i].rightdown.x=a[i].rightup.x;
		a[i].rightdown.y=a[i].leftdown.y;
		l[(i-1)*4+1]=Line(a[i].leftdown,a[i].leftup);
		l[(i-1)*4+2]=Line(a[i].leftup,a[i].rightup);
		l[(i-1)*4+3]=Line(a[i].rightup,a[i].rightdown);
		l[(i-1)*4+4]=Line(a[i].rightdown,a[i].leftdown);
		poly[(i-1)*4+1]=a[i].leftup;
		poly[(i-1)*4+2]=a[i].rightup;
		poly[(i-1)*4+3]=a[i].rightdown;
		poly[(i-1)*4+4]=a[i].leftdown;
	}
	for(int i=1;i<=m;i++)
	{
		c[i].input();
	}
	s.input();t.input();
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=m;j++)//圆圆相连 
		{
			if(i!=j)
			{
				double dis=c[i].distance(c[j]);
				if(dis<=R)
				{
					insert(n*4+i,n*4+j,0);
					continue;
				}
				Circle cir=Circle(c[i],R);
				Line temp=Line(c[i],c[j]);
				Point kkk1,kkk2;
				int pot=cir.pointcrossline(temp,kkk1,kkk2);
				if(temp.dispointtoseg(kkk1)>eps) kkk1=kkk2;
				temp=Line(kkk1,c[j]);
				if(!check(kkk1)) continue;
				int flag=1;
				int group=0; 
				for(int k=1;k<=4*n;k++)
				{
					if(k%4==1) group=0;
					int rel=temp.ifcrossline(l[k]);
					if(rel==1)
					{
						group++;
						if(group==4)
						{
							flag=0;
							break;
						}
						Point kkk=temp.crosspoint(l[k]);
						if(kkk==l[k].e||kkk==l[k].s) continue;
						if(temp.linecrossline(l[k])==1) continue;
						flag=0;
						break;
					}
				}
				if(flag) insert(n*4+i,n*4+j,dis-R);
			}
		}
		for(int j=1;j<=4*n;j++)//圆矩相连 
		{
			double dis=c[i].distance(poly[j]);
			if(dis<=R)
			{
				insert(n*4+i,j,0);
				continue;
			}
			Circle cir=Circle(c[i],R);
			Line temp=Line(c[i],poly[j]);
			Point kkk1,kkk2;
			int pot=cir.pointcrossline(temp,kkk1,kkk2);
			if(temp.dispointtoseg(kkk1)>eps) kkk1=kkk2;
			temp=Line(kkk1,poly[j]);
			if(!check(kkk1)) continue;
			int flag=1;
			int group=0; 
			for(int k=1;k<=4*n;k++)
			{
				if(k%4==1) group=0;
				int rel=temp.ifcrossline(l[k]);
				if(rel==1)
				{
					group++;
					if(group==4)
					{
						flag=0;
						break;
					}
					Point kkk=temp.crosspoint(l[k]);
					if(kkk==l[k].e||kkk==l[k].s) continue;
					if(temp.linecrossline(l[k])==1) continue;
					flag=0;
					break;
				}
			}
			if(flag) insert(n*4+i,j,dis-R);
		}
	}
	for(int i=1;i<=n;i++)//矩形自连 
	{
		insert((i-1)*4+1,(i-1)*4+2,a[i].leftup.distance(a[i].rightup));
		insert((i-1)*4+2,(i-1)*4+1,a[i].leftup.distance(a[i].rightup));
		insert((i-1)*4+2,(i-1)*4+3,a[i].rightup.distance(a[i].rightdown));
		insert((i-1)*4+3,(i-1)*4+2,a[i].rightup.distance(a[i].rightdown));
		insert((i-1)*4+3,(i-1)*4+4,a[i].rightdown.distance(a[i].leftdown));
		insert((i-1)*4+4,(i-1)*4+3,a[i].rightdown.distance(a[i].leftdown));
		insert((i-1)*4+4,(i-1)*4+1,a[i].leftdown.distance(a[i].leftup));
		insert((i-1)*4+1,(i-1)*4+4,a[i].leftdown.distance(a[i].leftup));
	}
	for(int i=1;i<=4*n;i++)
	{
		for(int j=1;j<=4*n;j++)//矩矩相连 
		{
			if(i==j) continue;
			int test1=i/4+(i%4==0? 0:1);
			int test2=j/4+(j%4==0? 0:1);
			if(test1==test2) continue;
			Line temp=Line(poly[i],poly[j]);
			int flag=1;
			int group=0; 
			for(int k=1;k<=4*n;k++)
			{
				if(k%4==1) group=0;
				int rel=temp.ifcrossline(l[k]);
				if(rel==1)
				{
					group++;
					if(group==4)
					{
						flag=0;
						break;
					}
					Point kkk=temp.crosspoint(l[k]);
					if(kkk==l[k].e||kkk==l[k].s) continue;
					if(temp.linecrossline(l[k])==1) continue;
					flag=0;
					break;
				}
			}
			if(flag) insert(i,j,poly[i].distance(poly[j]));
		}
	}
	for(int i=1;i<=4*n;i++)//矩形连圆 
	{
		for(int j=1;j<=m;j++)
		{
			Line temp=Line(poly[i],c[j]);
			int flag=1;
			int group=0; 
			for(int k=1;k<=4*n;k++)
			{
				if(k%4==1) group=0;
				int rel=temp.ifcrossline(l[k]);
				if(rel==1)
				{
					group++;
					if(group==4)
					{
						flag=0;
						break;
					}
					Point kkk=temp.crosspoint(l[k]);
					if(kkk==l[k].e||kkk==l[k].s) continue;
					if(temp.linecrossline(l[k])==1) continue;
					flag=0;
					break;
				}
			}
			if(flag) insert(i,n*4+j,poly[i].distance(c[j]));
		}
	}
	for(int i=1;i<=4*n;i++)
	{
		Line temp=Line(s,poly[i]);
		int flag=1;
		int group=0; 
		for(int k=1;k<=4*n;k++)
		{
			if(k%4==1) group=0;
			int rel=temp.ifcrossline(l[k]);
			if(rel==1)
			{
				group++;
				if(group==4)
				{
					flag=0;
					break;
				}
				Point kkk=temp.crosspoint(l[k]);
				if(kkk==l[k].e||kkk==l[k].s) continue;
				if(temp.linecrossline(l[k])==1) continue;
				flag=0;
				break;
			}
		}
		if(flag) insert(0,i,s.distance(poly[i]));
		temp=Line(t,poly[i]);
		flag=1;
		group=0; 
		for(int k=1;k<=4*n;k++)
		{
			if(k%4==1) group=0;
			int rel=temp.ifcrossline(l[k]);
			if(rel==1)
			{
				group++;
				if(group==4)
				{
					flag=0;
					break;
				}
				Point kkk=temp.crosspoint(l[k]);
				if(kkk==l[k].e||kkk==l[k].s) continue;
				if(temp.linecrossline(l[k])==1) continue;
				flag=0;
				break;
			}
		}
		if(flag) insert(i,n*4+m+1,t.distance(poly[i]));
	}
	for(int i=1;i<=m;i++)
	{
		Line temp=Line(s,c[i]);
		int flag=1;
		int group=0; 
		for(int k=1;k<=4*n;k++)
		{
			if(k%4==1) group=0;
			int rel=temp.ifcrossline(l[k]);
			if(rel==1)
			{
				group++;
				if(group==4)
				{
					flag=0;
					break;
				}
				Point kkk=temp.crosspoint(l[k]);
				if(kkk==l[k].e||kkk==l[k].s) continue;
				if(temp.linecrossline(l[k])==1) continue;
				flag=0;
				break;
			}
		}
		if(flag) insert(0,n*4+i,s.distance(c[i]));
	}
	for(int i=1;i<=m;i++)
	{
		double dis=t.distance(c[i]);
		if(dis<=R)
		{
			insert(4*n+i,4*n+m+1,0);
			continue;
		}
		Circle cir=Circle(c[i],R);
		Line temp=Line(c[i],t);
		Point kkk1,kkk2;
		int pot=cir.pointcrossline(temp,kkk1,kkk2);
		if(temp.dispointtoseg(kkk1)>eps) kkk1=kkk2;
		temp=Line(kkk1,t);
		if(!check(kkk1)) continue;
		int flag=1;
		int group=0; 
		for(int k=1;k<=4*n;k++)
		{
			if(k%4==1) group=0;
			int rel=temp.ifcrossline(l[k]);
			if(rel==1)
			{
				group++;
				if(group==4)
				{
					flag=0;
					break;
				}
				Point kkk=temp.crosspoint(l[k]);
				if(kkk==l[k].e||kkk==l[k].s) continue;
				if(temp.linecrossline(l[k])==1) continue;
				flag=0;
				break;
			}
		}
		if(flag) insert(4*n+i,4*n+m+1,dis-R);
	}
	Line temp=Line(s,t);
	int flag=1;
	int group=0; 
	for(int k=1;k<=4*n;k++)
	{
		if(k%4==1) group=0;
		int rel=temp.ifcrossline(l[k]);
		if(rel==1)
		{
			group++;
			if(group==4)
			{
				flag=0;
				break;
			}
			Point kkk=temp.crosspoint(l[k]);
			if(kkk==l[k].e||kkk==l[k].s) continue;
			if(temp.linecrossline(l[k])==1) continue;
			flag=0;
			break;
		}
	}
	if(flag) insert(0,4*n+m+1,s.distance(t));
	for(int i=1;i<=m;i++)
	{
		Circle temp=Circle(c[i],R);
		for(int k=1;k<=4*n;k++)
		{
			Point kkk1,kkk2;
			int pot=temp.pointcrossline(l[k],kkk1,kkk2);
			if(pot==0) continue;
			else
			{
				if(l[k].dispointtoseg(kkk1)<=eps)
				{
					bia++;
					int rod=k/4+(k%4==0? 0:1);
					fa[bia]=rod;
					sp[bia]=kkk1;
					insert(4*n+i,4*n+m+1+bia,0);
					insert(4*n+m+1+bia,k,kkk1.distance(poly[k]));
					insert(4*n+m+1+bia,k-1+((k-1)%4==0? 4:0),kkk1.distance(poly[k-1+((k-1)%4==0? 4:0)]));
				}
				if(l[k].dispointtoseg(kkk2)<=eps)
				{
					bia++;
					int rod=k/4+(k%4==0? 0:1);
					fa[bia]=rod;
					sp[bia]=kkk2;
					insert(4*n+i,4*n+m+1+bia,0);
					insert(4*n+m+1+bia,k,kkk2.distance(poly[k]));
					insert(4*n+m+1+bia,k-1+((k-1)%4==0? 4:0),kkk2.distance(poly[k-1+((k-1)%4==0? 4:0)]));
				}
			}
		}
	}
	for(int i=1;i<=bia;i++)
	{
		for(int j=1;j<=m;j++)
		{
			Line temp=Line(sp[i],c[j]);
			int flag=0;
			int group=0;
			for(int k=1;k<=4*n;k++)
			{
				if(k%4==1) group=0;
				int rel=temp.ifcrossline(l[k]);
				if(rel==1)
				{
					group++;
					if(group==4)
					{
						flag=2;
						break;
					}
					if(k/4+(k%4==0? 0:1)==fa[i])
					{
						flag++;
						continue;
					}
					Point kkk=temp.crosspoint(l[k]);
					if(kkk==l[k].e||kkk==l[k].s) continue;
					if(temp.linecrossline(l[k])==1) continue;
					flag++;
				}
			}
			if(flag<=1) insert(4*n+m+1+i,n*4+j,sp[i].distance(c[j]));
		}
		for(int j=1;j<=4*n;j++)
		{
			Line temp=Line(sp[i],poly[j]);
			int flag=0;
			int group=0;
			for(int k=1;k<=4*n;k++)
			{
				if(k%4==1) group=0;
				int rel=temp.ifcrossline(l[k]);
				if(rel==1)
				{
					group++;
					if(group==4)
					{
						flag=2;
						break;
					}
					if(k/4+(k%4==0? 0:1)==fa[i])
					{
						flag++;
						continue;
					}
					Point kkk=temp.crosspoint(l[k]);
					if(kkk==l[k].e||kkk==l[k].s) continue;
					if(temp.linecrossline(l[k])==1) continue;
					flag++;
				}
			}
			if(flag<=1) insert(4*n+m+1+i,j,sp[i].distance(poly[j]));
		}
		Line temp=Line(sp[i],t);
		int flag=0;
		int group=0;
		for(int k=1;k<=4*n;k++)
		{
			if(k%4==1) group=0;
			int rel=temp.ifcrossline(l[k]);
			if(rel==1)
			{
				group++;
				if(group==4)
				{
					flag=2;
					break;
				}
				if(k/4+(k%4==0? 0:1)==fa[i])
				{
					flag++;
					continue;
				}
				Point kkk=temp.crosspoint(l[k]);
				if(kkk==l[k].e||kkk==l[k].s) continue;
				if(temp.linecrossline(l[k])==1) continue;
				flag++;
			}
		}
		if(flag<=1) insert(4*n+m+1+i,4*n+m+1,sp[i].distance(t));
	}
	dijkstra();
	printf("%.9lf\n",dis[4*n+m+1]);
	return 0;
}

C++(g++ 7.5.0) 解法, 执行用时: 2855ms, 内存消耗: 14716K, 提交时间: 2022-09-24 20:13:43

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ldb;
const ldb eps = 1e-14;

int sgn(ldb x){
	if(x > eps) return 1;
	if(x < -eps) return -1;
	return 0;
}

struct point{
	ldb x,y;
	point() : x(), y() {}
	point(ldb _x,ldb _y) : x(_x), y(_y) {}
};
point operator + (point x,point y){
	x.x += y.x; x.y += y.y;
	return x;
}
point operator - (point x,point y){
	x.x -= y.x; x.y -= y.y;
	return x;
}
point operator * (ldb x,point y){
	y.x *= x; y.y *= x;
	return y;
}
bool operator == (point p1,point p2){
	return sgn(p1.x - p2.x) == 0 && sgn(p1.y - p2.y) == 0;
}

struct line{
	point a,b;
	line() : a(), b() {}
	line(point _a,point _b) : a(_a), b(_b) {}
};

ldb dist(point p1,point p2){
	return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}

ldb len(point p1){
	return sqrt(p1.x * p1.x + p1.y * p1.y);
}

ldb det(point p1,point p2){
	return p1.x * p2.y - p1.y * p2.x;
}

ldb dot(point p1,point p2){
	return p1.x * p2.x + p1.y * p2.y;
}

bool intersec(line x,line y){
	return sgn(det(x.a - y.a,y.b - y.a) * det(x.b - y.a,y.b - y.a)) <= 0;
}

bool exclusion_test(line x,line y){
	return sgn(min(x.a.x,x.b.x) - max(y.a.x,y.b.x)) <= 0 && sgn(min(y.a.x,y.b.x) - max(x.a.x,x.b.x)) <= 0 && sgn(min(x.a.y,x.b.y) - max(y.a.y,y.b.y)) <= 0 && sgn(min(y.a.y,y.b.y) - max(x.a.y,x.b.y)) <= 0;
}

bool seg_intersec(line x,line y){
	return exclusion_test(x,y) && intersec(x,y) && intersec(y,x);
}

bool point_on_seg(point x,line y){
	return sgn(dot(y.a - x,y.b - x)) <= 0 && sgn(det(y.a - x,y.b - x)) == 0;
}

ldb distp(point x,line y){
	return fabs(det(y.a - x,y.b - x)) / len(y.b - y.a);
}

point project_point(point x,line y){
	point v = y.b - y.a;
	return y.a + (dot(v,x - y.a) / dot(v,v)) * v;
}

int n,m,R;
line ob[305];
point s[30005]; int sc = 0,obc = 0;

struct node{
	int x; ldb dis;
	node(int _x = 0,ldb _dis = 0.0) : x(_x), dis(_dis) {}
	bool operator < (const node &nd)const{
		return nd.dis < dis;
	}
};
priority_queue <node> pq;
int ec = 0,to[30000005],nxt[30000005],hed[30005];
ldb w[30000005];
void add_edge(int f,int t,ldb cst){
	++ ec; to[ec] = t; nxt[ec] = hed[f]; hed[f] = ec; w[ec] = cst;
}
ldb dis[30005]; int vis[30005];
void dijkstra(int s){
	for(int i = 1;i <= sc;i ++) dis[i] = 1e18;
	pq.push(node(s,0.0));
	dis[s] = 0.0; vis[s] = 0;
	while(!pq.empty()){
		node h = pq.top(); pq.pop();
		int u = h.x;
		if(vis[u]) continue;
		vis[u] = 1;
		for(int v,i = hed[u];i;i = nxt[i]){
			v = to[i];
			if(dis[v] > dis[u] + w[i]){
				dis[v] = dis[u] + w[i];
				pq.push(node(v,dis[v]));
			}
		}
	}
}

int type2,type3;
bool judge(point x,point y){
	for(int k = 2;k + 4 < type2;k += 4){
		if(!point_on_seg(s[k + 1],line(x,y)) && !point_on_seg(s[k + 3],line(x,y)) && seg_intersec(line(s[k + 1],s[k + 3]),line(x,y))) return 1;
		if(!point_on_seg(s[k + 2],line(x,y)) && !point_on_seg(s[k + 4],line(x,y)) && seg_intersec(line(s[k + 2],s[k + 4]),line(x,y))) return 1;
	}
	return 0;
}

bool judge2(point x){
	for(int k = 2;k + 4 < type2;k += 4){
		ldb xl = s[k + 1].x,yl = s[k + 1].y,xr = s[k + 3].x,yr = s[k + 3].y;
		if(xl + eps < x.x && x.x + eps < xr && yl + eps < x.y && x.y + eps < yr) return 1;
	}
	return 0;
}

point lcsec[3];
int sec_line_circle(line x,ldb cx,ldb cy,ldb cr,point *ret){
	ldb dis = distp(point(cx,cy),x);
	if(sgn(dis - cr) > 0) return 0;
	point proj = project_point(point(cx,cy),x);
	if(sgn(dis - cr) == 0){
		ret[0] = proj;
		return 1;
	}
	point v = x.b - x.a; ldb dv = sqrt(cr * cr - dis * dis);
	ret[0] = proj + (dv / len(v)) * v;
	ret[1] = proj - (dv / len(v)) * v;
	return 2;
}

int main(){
	ios::sync_with_stdio(false);
	// S = 1, T = 2
	sc = 2;
	cin >> n >> m >> R;
	for(int xl,yl,xr,yr,i = 1;i <= n;i ++){
		cin >> xl >> yl >> xr >> yr;
		s[++ sc] = point(xl,yl);
		s[++ sc] = point(xl,yr);
		s[++ sc] = point(xr,yr);
		s[++ sc] = point(xr,yl);
		ob[++ obc] = line(point(xl,yl),point(xl,yr));
		ob[++ obc] = line(point(xl,yr),point(xr,yr));
		ob[++ obc] = line(point(xr,yr),point(xr,yl));
		ob[++ obc] = line(point(xr,yl),point(xl,yl));
	}
	type2 = sc + 1;
	for(int x,y,i = 1;i <= m;i ++){
		cin >> x >> y;
		s[++ sc] = point(x,y);
	}
	type3 = sc + 1;
	for(int i = type2;i < type3;i ++){
		for(int j = 1;j <= obc;j ++){
			int cnt = sec_line_circle(ob[j],s[i].x,s[i].y,R,lcsec);
			//cout << "CIRC: " << i << ' ' << j << ' ' << cnt << endl;
			for(int k = 0;k < cnt;k ++){
				//cout << s[i].x << ',' << s[i].y << ' ' << lcsec[k].x << ',' << lcsec[k].y << ' ' << dist(s[i],lcsec[k]) << endl;
				if(point_on_seg(lcsec[k],line(ob[j]))) s[++ sc] = lcsec[k];
			}
		}
	}
	cin >> s[1].x >> s[1].y >> s[2].x >> s[2].y;
	//cout << type3 << ' ' << sc << endl;
	for(int i = 1;i <= sc;i ++){
		//cout << i << ' ' << s[i].x << ' ' << s[i].y << '\n';
		for(int j = 1;j <= sc;j ++){
			if(s[i] == s[j]) continue;
			if(i >= type3 && j >= type3) break;
			
			ldb dis = dist(s[i],s[j]);
			point tmp = s[i];
			if(i >= type2 && i < type3){
				dis = max((ldb)(0.0),dis - R);
				if(dis <= eps){
					add_edge(i,j,dis);
					continue;
				}
				s[i] = s[i] + (1.0 * R / len(s[j] - s[i])) * (s[j] - s[i]);
				if(judge2(s[i])) dis = 1e18;
			}
			if(judge(s[i],s[j])) dis = 1e18;
			s[i] = tmp;
			//cout << i << ',' << j << ',' << dis << endl;
			if(dis < 1e17) add_edge(i,j,dis);
		}
	}
	dijkstra(1);
	cout << fixed << setprecision(14) << dis[2] << '\n';
	return 0;
}

上一题