• [ICPC World Finals 2018][LOJ6409]熊猫保护区(voronoi图)


    题面

    https://loj.ac/problem/6409

    题解

    前置知识

    首先转化题意,相当于求多边形内的某一个点,使得这个点到多边形的各定点的距离的最小值最大,输出这个距离。

    先求出所有多边形顶点的voronoi图。由voronoi图的性质,对于一个点v和一个多边形顶点u,v到u的距离是v到所有点的距离的最小值当且仅当v在voronoi图中u管辖的区域的内部或边上。所以对于每一个多边形顶点u,“u到voronoi图中它管辖的区域原多边形的交集中,距离最大的点的距离”的最大值就是答案。

    • 性质:对于一个点u和一个多边形A,A中距离u最远的点一定是A的某个顶点。

    考虑对于一个多边形顶点u,图形“voronoi图中它管辖的区域原多边形的交集”的顶点是什么。不可能有除了u以外的其他顶点;可以是voronoi图中的顶点,也可以是voronoi图中的边和多边形边的交点。

    所以,原题要求的点只有两种可能性:

    1. 是voronoi图的某个顶点。
    2. 是voronoi图中的某条线和原多边形的某条边的交点。

    对于1,由于voronoi图只有O(n)个顶点,枚举这些点,再枚举多边形上的点,(O(n^2))暴力即可。

    对于2,对于voronoi图中一条线l和多边形某条边的交点p,设l是多边形顶点(A_i)(A_j)的中垂线,只用计算p到(A_i)(A_j)的距离即可。交点共(O(n^2))个,更新答案用时(O(1))

    综上,本题时间复杂度为(O(n^2))

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define rg register
    #define ld long double
    #define In inline
    
    const ld eps = 1e-9;
    const ld inf = 1e9;
    const int N = 2000;
    
    In int read(){
    	int s = 0,ww = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
    	while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
    	return s * ww;
    }
    
    In int sgn(ld x){return x < -eps ? -1 : x > eps;}
    
    In ld sqr(ld x){return x * x;}
    
    struct vec{
    	ld x,y;
    	vec(){}
    	vec(ld _x,ld _y){x = _x,y = _y;}
    	In friend vec operator + (vec a,vec b){
    		return vec(a.x + b.x,a.y + b.y);
    	}
    	In friend vec operator - (vec a,vec b){
    		return vec(a.x - b.x,a.y - b.y);
    	}
    	In friend vec operator * (vec a,ld k){
    		return vec(a.x * k,a.y * k);
    	}
    	In friend vec operator / (vec a,ld k){
    		return vec(a.x / k,a.y / k);
    	}
    	In friend bool operator == (vec a,vec b){
    		return sgn(a.x - b.x) == 0 && sgn(a.y - b.y) == 0;
    	}
    	In friend ld Dot(vec a,vec b){
    		return a.x * b.x + a.y * b.y;
    	}
    	In friend ld Cross(vec a,vec b){
    		return a.x * b.y - a.y * b.x;
    	}
    	In friend ld len(vec a){
    		return sqrt(sqr(a.x) + sqr(a.y));
    	}
    	In friend bool InUpper(vec a){
    		int k;
    		return ((k=sgn(a.y)) > 0 || (k==0&&sgn(a.x)>0));
    	}
    	In friend bool prl(vec a,vec b){
    		return sgn(Cross(a,b)) == 0;
    	}
    	In friend bool samedir(vec a,vec b){
    		return prl(a,b) && sgn(Dot(a,b)) > 0;
    	}
    };
    
    struct line{
    	vec p,v;
    	int vx,vy;
    	line(){}
    	line(vec _p,vec _v){p = _p,v = _v;}
    	line(vec _p,vec _v,int _vx,int _vy){p = _p,v = _v,vx = _vx,vy = _vy;}
    	In friend vec Its(line a,line b){
    		ld x = Cross(b.v,a.p - b.p),y = Cross(a.v,b.v);
    		return a.p + a.v * x / y;
    	}
    	In friend bool include(line a,vec p){
    		return sgn(Cross(a.v,p-a.p)) > 0;
    	}
    };
    
    In bool HaveIts(ld l1,ld r1,ld l2,ld r2){
    	if(l1 > r1)swap(l1,r1);
    	if(l2 > r2)swap(l2,r2);
    	if(sgn(r1-l2) < 0 || sgn(r2-l1) < 0)return 0;
    	return 1;
    }
    
    struct seg{
    	vec p1,p2;
    	int vx,vy;
    	seg(){}
    	seg(vec _p1,vec _p2){p1 = _p1,p2 = _p2;}
    	seg(vec _p1,vec _p2,int _vx,int _vy){p1 = _p1,p2 = _p2,vx = _vx,vy = _vy;}
    	In friend bool HaveIts(seg a,seg b){
    		return HaveIts(a.p1.x,a.p2.x,b.p1.x,b.p2.x) 
    			&& HaveIts(a.p1.y,a.p2.y,b.p1.y,b.p2.y)
    			&& sgn(Cross(a.p2-a.p1,b.p1-a.p1)) * sgn(Cross(a.p2-a.p1,b.p2-a.p1)) <= 0
    			&& sgn(Cross(b.p2-b.p1,a.p1-b.p1)) * sgn(Cross(b.p2-b.p1,a.p2-b.p1)) <= 0;
    	}
    	In friend vec Its(seg a,seg b){
    		return Its(line(a.p1,a.p2-a.p1),line(b.p1,b.p2-b.p1));
    	}
    	In friend ld dis(vec p,seg a){
    		return abs(Cross(a.p2-p,a.p1-p) / len(a.p2-a.p1));
    	}
    	In friend bool OnSeg(vec p,seg a){
    		if(p == a.p1 || p == a.p2)return 1;
    		return sgn(dis(p,a)) == 0 && sgn(Dot(a.p1-p,a.p2-p)) < 0;
    	}
    };
    
    bool inside(vec p,seg l[],int n){//0:out,1:on,2:out
    	int rt = 0;
    	for(rg int i = 1;i <= n;i++){
    		if(OnSeg(p,l[i]))return 1;
    		seg s = l[i];
    		if(s.p1.y < s.p2.y)swap(s.p1,s.p2);
    		if(sgn(p.y-s.p1.y) >= 0 || sgn(p.y-s.p2.y) < 0)continue;
    		rt ^= (sgn(Cross(p-s.p1,p-s.p2)) > 0);
    	}
    	return rt << 1;
    }
    
    vec V[N*N+5]; //v图的点,最终是O(n)个,但是过程中可能有很多
    seg E[N*N+5]; 
    int Vn,En;
    
    In bool check(line x,line y,line z){
    	return include(z,Its(x,y));
    }
    
    In bool small(line a){
    	return fabs(a.p.x) < inf / 2 && fabs(a.p.y) < inf / 2;
    }
    
    In bool cmp3(line a,line b){
    	bool k1 = InUpper(a.v),k2 = InUpper(b.v);
    	if(k1 != k2)return k1 < k2;
    	return sgn(Cross(a.v,b.v)) > 0;
    }
    
    In bool cmp4(line a,line b){
    	if(samedir(a.v,b.v))return include(b,a.p);
    	return cmp3(a,b);
    }
    
    vec I[N+5];
    
    void HalfPlaneIts(line l[],int ln){
    	l[++ln] = line(vec(-inf,-inf),vec(1,0));
    	l[++ln] = line(vec(inf,-inf),vec(0,1));
    	l[++ln] = line(vec(inf,inf),vec(-1,0));
    	l[++ln] = line(vec(-inf,inf),vec(0,-1));
    	sort(l + 1,l + ln + 1,cmp4);
    	deque<line>q;
    	q.clear();
    	for(rg int i = 1;i <= ln;i++){
    		if(i > 1 && samedir(l[i-1].v,l[i].v))continue;
    		while(q.size() > 1 && !check(q[q.size()-2],q[q.size()-1],l[i]))q.pop_back();
    		while(q.size() > 1 && !check(q[1],q[0],l[i]))q.pop_front();
    		q.push_back(l[i]);
    	}
    	while(q.size() > 2 && ! check(q[q.size()-2],q[q.size()-1],q[0]))q.pop_back();
    	for(rg int i = 0;i < q.size();i++)I[i] = Its(q[i],q[(i+1)%q.size()]);
    	for(rg int i = 0;i < q.size();i++)if(small(q[i]))E[++En] = seg(I[(i+q.size()-1)%q.size()],I[i],q[i].vx,q[i].vy);
    	for(rg int i = 0;i < q.size();i++)if(small(q[i]) && small(q[(i+1)%q.size()]))V[++Vn] = I[i];
    }
    
    int n;
    vec a[N+5]; //多边形的点
    seg l[N+5]; //多边形的边
    line temp[N+5];
    
    In bool cmp1(vec a,vec b){
    	int k;
    	if((k=sgn(a.x-b.x)) != 0)return k < 0;
    	return sgn(a.y - b.y) < 0;
    }
    
    In bool cmp2(vec a,vec b){
    	return sgn(a.x - b.x) == 0 && sgn(a.y - b.y) == 0;
    }
    
    int main(){
    	n = read();
    	for(rg int i = 1;i <= n;i++){
    		int x = read(),y = read();
    		a[i] = vec(x,y);
    	}
    	for(rg int i = 1;i <= n;i++)l[i] = seg(a[i],a[i%n+1]);
    	for(rg int i = 1;i <= n;i++){
    		int cnt = 0;
    		for(rg int j = 1;j <= n;j++)if(i != j)temp[++cnt] = line((a[i]+a[j]) / 2,vec(a[i].y-a[j].y,a[j].x-a[i].x),i,j);
    		HalfPlaneIts(temp,cnt);
    	}
    	sort(V + 1,V + Vn + 1,cmp1);
    	Vn = unique(V + 1,V + Vn + 1,cmp2) - V - 1;
    	ld ans = 0;
    	for(rg int i = 1;i <= Vn;i++){
    		if(!inside(V[i],l,n))continue;
    		ld cur = 1e12;
    		for(rg int j = 1;j <= n;j++)cur = min(cur,len(a[j]-V[i]));
    		ans = max(ans,cur);
    	}
    	for(rg int i = 1;i <= En;i++){
    		if(InUpper(E[i].p2-E[i].p1))continue;
    		for(rg int j = 1;j <= n;j++)if(HaveIts(E[i],l[j])){
    			vec p;
    			if(prl(E[i].p2-E[i].p1,l[j].p2-l[j].p1))continue;
    			else p = Its(E[i],l[j]);
    			ld cur = 1e12;		
    			cur = min(cur,len(a[E[i].vx]-p));
    			cur = min(cur,len(a[E[i].vy]-p));
    			ans = max(ans,cur);
    		}
    	}
    	printf("%.9lf
    ",(double)ans);
    	return 0;
    }
    
    
  • 相关阅读:
    博客园美化-SimpleMemor
    Java多线程-synchronized与ReentrantLock
    springboot中删除@SessionAttributes注解的属性
    SSM整合笔记
    Spring中xml和注解方式使用AOP
    Mysql 数据库基本操作
    Mysql 二进制包安装
    named piped tcp proxy 下载
    docker容器中日志文件过大处理方法
    自动做bond的脚本
  • 原文地址:https://www.cnblogs.com/xh092113/p/12360886.html
Copyright © 2020-2023  润新知