• [HDU3151]Cave Crisis


    XXX.[HDU3151]Cave Crisis

    一眼看上去跟XII.[ABC181F]Silver Woods完全一致,因此考虑一样的思路。

    于是我们现在问题变为求出两个多边形间的距离。

    首先先考虑如何判断它们是否有交。有交只有一种可能,就是边有交。于是我们枚举两个多边形所有的边,然后判断它们是否有交。具体而言,我们求出两条边所在直线的交点,然后用点积判断该交点是否都在两条线段上即可。

    但是我一开始没想通还写了个判断点是否在另一个多边形内部的代码,但显然此种情形是可以被前一种完美包含的。但是这确实有用——这让我不必去判断两条线段是否平行,因为平行且相交只能是有一条线段其中某个点在另一条线段上,也即在另一个多边形的边界上,但是此种情形我已经在内部判断过了(这里的内部包含边界)。

    然后就是求距离了。距离只有两种可能,点到边,点到点。点到点很好算,直接 \(n^2\) 枚举即可,关键是点到边。我采取的方式是作出点到边的垂线,然后计算垂线与原直线的交点,然后判断该交点是否在线段上,不是则计算到两线段端点距离的较小值,是则计算到该交点的距离。

    搞完之后排个序冰茶姬维护就行了。

    但需要注意的是,上一题的起点是 \((-\infty,0)\),但是本题的起点却是 \((0,0)\)!这意味着在起点处就不能拥有太大的半径,最终答案需要与起点到所有多边形的最小距离取 \(\min\)

    但又一个坑点出现了:该最小距离是半径,但是我们上文计算出的两多边形间距离却是直径!

    千疮百孔的代码:

    #include<bits/stdc++.h>
    using namespace std;
    const double eps=1e-12;
    int m,n;
    int cmp(double x){
    	if(x>eps)return 1;
    	if(x<-eps)return -1;
    	return 0;
    }
    struct Vector{
    	double x,y;
    	Vector(){}
    	Vector(double X,double Y){x=X,y=Y;}
    	friend Vector operator +(const Vector &u,const Vector &v){return Vector(u.x+v.x,u.y+v.y);}
    	friend Vector operator -(const Vector &u,const Vector &v){return Vector(u.x-v.x,u.y-v.y);}
    	friend Vector operator *(const Vector &u,const double &v){return Vector(u.x*v,u.y*v);}
    	friend Vector operator /(const Vector &u,const double &v){return Vector(u.x/v,u.y/v);}
    	friend double operator &(const Vector &u,const Vector &v){return u.x*v.y-u.y*v.x;}//cross times
    	friend double operator |(const Vector &u,const Vector &v){return u.x*v.x+u.y*v.y;}//point times
    	double operator ~()const{return sqrt(x*x+y*y);}//the modulo of a vector
    	double operator !()const{return atan2(y,x);}//the angle of a vector
    	void read(){scanf("%lf%lf",&x,&y);}
    	void print()const{printf("(%lf,%lf)",x,y);}
    };
    typedef Vector Point;
    struct Line{
    	Point x,y;
    	Vector z;
    	Line(){}
    	Line(Point X,Point Y){x=X,y=Y,z=Y-X;}
    	friend Point operator &(const Line &u,const Line &v){return u.x+u.z*((v.z&(u.x-v.x))/(u.z&v.z));}
    	friend double operator-(const Line &u,const Point &v){//calculate the distance between u and v
    		Line w(v,Point(v.x+u.z.y,v.y-u.z.x));
    		Point o=(u&w);
    		if(cmp((o-u.x)|(o-u.y))!=1)return ~(o-v);
    		return min(~(u.x-v),~(u.y-v));
    	}
    };
    typedef Line Segment;
    vector<Point>v[110];
    struct edge{
    	int u,v;
    	double w;
    	edge(int U,int V,double W){u=U,v=V,w=W;}
    	friend bool operator<(const edge&u,const edge&v){return u.w<v.w;}
    };
    vector<edge>u;
    int dsu[110];
    int find(int x){return dsu[x]==x?x:dsu[x]=find(dsu[x]);}
    void merge(int x,int y){
    	x=find(x),y=find(y);
    	if(x==y)return;
    	dsu[y]=x;
    }
    bool same(int x,int y){return find(x)==find(y);}
    int main(){
    	while(true){
    		scanf("%d%d",&m,&n);
    		if(!m&&!n)return 0;
    		for(int i=1,z;i<=n;i++){
    			v[i].clear();
    			Vector V;
    			scanf("%d",&z);
    			while(z--)V.read(),v[i].push_back(V);
    		}
    		u.clear();
    		for(int i=1;i<=n;i++){
    			for(int j=1;j<=n;j++){
    				if(i==j)continue;
    				double dis=0x3f3f3f3f;
    				for(auto I:v[i]){
    					bool in=true;//if a point is inside the other graph
    					for(int J=0;J<v[j].size();J++)if(cmp((v[j][J]-I)&(v[j][(J+1)%v[j].size()]-I))==-1){in=false;break;}
    					if(in){dis=-1;break;}
    					for(int J=0;J<v[j].size();J++)dis=min(dis,Line(v[j][J],v[j][(J+1)%v[j].size()])-I);
    				}
    				for(int I=0;cmp(dis)==1&&I<v[i].size();I++)for(int J=0;J<v[j].size();J++){//if two segments intersect
    					Vector i1=v[i][I],i2=v[i][(I+1)%v[i].size()];
    					Vector j1=v[j][J],j2=v[j][(J+1)%v[j].size()];
    					if(cmp((i1-i2)&(j1-j2))==0)continue;//two segments parallel
    					Vector k=Line(i1,i2)&Line(j1,j2);
    //					i1.print(),i2.print(),j1.print(),j2.print(),k.print();puts("");
    					if(cmp((i1-k)|(i2-k))!=1&&cmp((j1-k)|(j2-k))!=1){dis=-1;break;}
    				}
    				u.emplace_back(i,j,dis);
    			}
    			double mx=-0x3f3f3f3f,mn=0x3f3f3f3f;
    			for(auto I:v[i])mx=max(mx,I.y),mn=min(mn,I.y);
    			u.emplace_back(n+1,i,m/2.0-mx),u.emplace_back(n+2,i,mn+m/2.0);
    		}
    		u.emplace_back(n+1,n+2,m);
    		for(int i=1;i<=n+2;i++)dsu[i]=i;
    		sort(u.begin(),u.end());
    //		for(auto i:u)printf("%d %d %lf\n",i.u,i.v,i.w);
    		double ans=0x3f3f3f3f;
    		for(int i=1;i<=n;i++)for(int I=0;I<v[i].size();I++)ans=min(ans,Line(v[i][I],v[i][(I+1)%v[i].size()])-Point(0,0));
    		ans*=2; 
    		for(int i=0;i<u.size();i++){
    			merge(u[i].u,u[i].v);
    			if(same(n+1,n+2)){if(cmp(min(ans,u[i].w))!=1)puts("impossible");else printf("%.2lf\n",min(ans,u[i].w)/2);break;}
    		}
    	}
    	return 0;
    } 
    
  • 相关阅读:
    吴裕雄--天生自然 诗经:天净沙·秋思
    阿里云Kubernetes服务
    一探究竟:善用 MaxCompute Studio 分析 SQL 作业
    MaxCompute Studio 使用入门
    AI 一体机,满足新时代的新需求
    OSS重磅推出OSS Select——使用SQL选取文件的内容
    如何将DynamoDB的数据增量迁移到表格存储
    多隆:淘宝第一行代码撰写者的程序世界
    专访阿里巴巴量子实验室:最强量子电路模拟器“太章”到底强在哪?
    饿了么CTO张雪峰:允许90后的技术人员“浮躁“一点
  • 原文地址:https://www.cnblogs.com/Troverld/p/14619466.html
Copyright © 2020-2023  润新知