zoukankan      html  css  js  c++  java
  • 【半平面交】JZOJ3297. 【SDOI2013】逃考

    Description

    矩形内任意一个点会被距离它最近的特殊点监控。求某起点到给定矩形外的一条路径上,最少会被多少个特殊点监控。(n<=600)

    Solution

    • 考虑一个特殊点它所能控制的平面,应该是它与其他特殊点的连边的中垂线取靠近它的那一侧的半平面交。
    • 那么起点处出发,通过将每一条围成半平面的边,将这个边两侧的半平面连一条边,边权为1,再找到起点所在的半平面,跑一个向边界的最短路即可。

    计算几何 (几个模板)

    1. 点的定义
    struct dot{
    	db x,y;
    	dot(db _x=0,db _y=0){x=_x,y=_y;}
    }
    
    1. 边的定义(angle表示与x轴正半轴的夹角,也就是极角)
    struct line{
    	dot a,b; int nm; db angle;
    	line(){}
    	line(dot _a,dot _b,int _nm){
    		a=_a,b=_b,nm=_nm;
    		angle=atan2(b.y-a.y,b.x-a.x);
    	}
    }
    
    1. 两个点的叉积
    db cro(dot a,dot b){
    	return a.x*b.y-b.x*a.y;
    }
    
    1. 直线到点的距离:运用叉积求出四边形的有向面积,再通过S=a*h求出h
    db distance(line l,dot p){
    	db S=cro(dot(l.b.x-l.a.x,l.b.y-l.a.y),dot(p.x-l.a.x,p.y-l.a.y));
    	return abs(S)/sqrt(sqr(l.a.x-l.b.x)+sqr(l.a.y-l.b.y));
    }
    
    1. 极角排序:当极角一样(也就是平行)的时候要选择距离原点最近的,也就是distance的用法。
    int cmp(line p,line q) {
    	if (abs(p.angle-q.angle)>ESP) 
    		return p.angle<q.angle;
     	return distance(p,tmp)<distance(q,tmp);
    }
    
    1. 两条直线的交点:这个很恶心,再加上我打得丑,并不是很清楚。
      参考 https://blog.csdn.net/abcjennifer/article/details/7584628
    dot cross(line l0,line l1){
    	db x0=l0.a.x,y0=l0.a.y,x1=l0.b.x,y1=l0.b.y;
    	db a0=y0-y1,b0=x1-x0,c0=x0*y1-x1*y0;
    	x0=l1.a.x,y0=l1.a.y,x1=l1.b.x,y1=l1.b.y;
    	db a1=y0-y1,b1=x1-x0,c1=x0*y1-x1*y0;
    	db D=a0*b1-a1*b0;
    	return dot((b0*c1-b1*c0)/D,(a1*c0-a0*c1)/D);
    }
    
    1. 判断一个点是否在直线的右侧:直接叉积判断有向面积的正负,如果向量a在b的右侧则a*b<0
    int right(dot a,dot b){
    	return (cro(a,b)<=0);
    }
    

    半平面交

    1. 排序
    2. 去重(平行线)
    3. 枚举排序后的边
    4. 删去无效的队头
    5. 删去无效的队尾
    6. 判断加入这条边后对平面有无影响有则加入
    • 什么才是无效的边?
    • 当队头(队尾)的两条边的交点在新加入边的右侧(假定半平面围成的点在所有边的左侧),那么队头或队尾就是没有用的。
    • 以此类推,新加入的边如果对于队尾和它的交点在队头的右侧,那么新加入的边也是无效的。
    • 参考blog:
      https://blog.csdn.net/qq_40861916/article/details/83541403

    其他: define sqr(x) (x•x) 居然对于sqr(a+b)有问题???

    最终代码

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define db double 
    #define maxn 700
    #define maxm 500000
    #define ESP 0.00000001
    using namespace std;
    
    struct dot{
    	db x,y;
    	dot(db _x=0,db _y=0){x=_x,y=_y;}
    } rel[maxn],s,M,tmp;
    struct line{
    	dot a,b; int nm; db angle;
    	line(){}
    	line(dot _a,dot _b,int _nm){
    		a=_a,b=_b,nm=_nm;
    		angle=atan2(b.y-a.y,b.x-a.x);
    	}
    } L[maxn];
    
    int T,n,i,j,k,tot,d[maxn],head,tail,st;
    db w,h,x,y;
    int em,e[maxm],nx[maxm],ls[maxn],dis[maxn],vis[maxn];
    
    db cro(dot a,dot b){
    	return a.x*b.y-b.x*a.y;
    }
    
    db sqr(db a){return a*a;}
    
    db distance(line l,dot p){
    	db S=cro(dot(l.b.x-l.a.x,l.b.y-l.a.y),dot(p.x-l.a.x,p.y-l.a.y));
    	return abs(S)/sqrt(sqr(l.a.x-l.b.x)+sqr(l.a.y-l.b.y));
    }
    
    int cmp(line p,line q) {
    	if (abs(p.angle-q.angle)>ESP) 
    		return p.angle<q.angle;
     	return distance(p,tmp)<distance(q,tmp);
    }
    
    dot cross(line l0,line l1){
    	db x0=l0.a.x,y0=l0.a.y,x1=l0.b.x,y1=l0.b.y;
    	db a0=y0-y1,b0=x1-x0,c0=x0*y1-x1*y0;
    	x0=l1.a.x,y0=l1.a.y,x1=l1.b.x,y1=l1.b.y;
    	db a1=y0-y1,b1=x1-x0,c1=x0*y1-x1*y0;
    	db D=a0*b1-a1*b0;
    	return dot((b0*c1-b1*c0)/D,(a1*c0-a0*c1)/D);
    }
    
    int onright(line a,line b,line c) {
    	dot p=cross(b,c);
    	return (cro(dot(a.b.x-a.a.x,a.b.y-a.a.y),dot(p.x-a.a.x,p.y-a.a.y))<=0);
    }
    
    void insert(int x,int y){
    	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
    	em++; e[em]=x; nx[em]=ls[y]; ls[y]=em;
    }
    
    int BFS(int st,int en){
    	memset(dis,127,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	int t=0,w=1;
    	d[1]=st,vis[st]=1,dis[st]=0;
    	while (t<w){
    		int x=d[++t];
    		for(int i=ls[x];i;i=nx[i]) if (!vis[e[i]]){
    			vis[e[i]]=1;
    			dis[e[i]]=dis[x]+1;
    			d[++w]=e[i];
    			if (e[i]==en) 
    				return dis[en];
    		}
    	}
    }
    
    int main(){
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d",&n);
    		scanf("%lf%lf%lf%lf",&w,&h,&s.x,&s.y);
    		for(i=1;i<=n;i++) scanf("%lf%lf",&rel[i].x,&rel[i].y);
    		if (n==0) {printf("0
    ");continue;}
    		em=0; memset(ls,0,sizeof(ls)); st=0;
    		for(i=1;i<=n;i++) {
    			//------insert---------
    			tot=0;
    			for(j=1;j<=n;j++) if (j!=i){
    				M.x=(rel[i].x+rel[j].x)/2;
    				M.y=(rel[i].y+rel[j].y)/2;
    				++tot,L[tot].a=M;
    				
    				x=M.x-rel[i].x,y=M.y-rel[i].y;
    				L[tot].b.x=M.x-y,L[tot].b.y=M.y+x;
    				
    				L[tot].nm=j;
    				L[tot].angle=atan2(L[tot].b.y-L[tot].a.y,L[tot].b.x-L[tot].a.x);
    			}
    			dot t1=dot(0,0),t2=dot(0,h),t3=dot(w,0),t4=dot(w,h);
    			L[++tot]=line(t2,t1,0),L[++tot]=line(t1,t3,0);
    			L[++tot]=line(t3,t4,0),L[++tot]=line(t4,t2,0);
    			//------Half plane intersection-------
    			tmp=rel[i];
    			sort(L+1,L+1+tot,cmp);
    			head=1,tail=0;
    			for(j=1;j<=tot;j++) {
    				if (j>1&&abs(L[j].angle-L[j-1].angle)<ESP) continue;
    				while (tail>1&&onright(L[j],L[d[tail-1]],L[d[tail]])) tail--;
    				while (head<tail&&onright(L[j],L[d[head]],L[d[head+1]])) head++;
    				if (!(head<tail&&onright(L[d[head]],L[j],L[d[tail]]))) d[++tail]=j;
    			}
    			int tp=1;
    			for(j=head;j<=tail;j++) {
    				insert(i,L[d[j]].nm);
    				line p=L[d[j]];
    				if (cro(dot(p.b.x-p.a.x,p.b.y-p.a.y),dot(s.x-p.a.x,s.y-p.a.y))<=0)
    					tp=0;
    			} 
    			if (tp) st=i;
    		}
    		printf("%d
    ",BFS(st,0));
    	}
    }
    
  • 相关阅读:
    【转】 Android代码混淆之混淆规则
    【转】java虚拟机机制总结
    【转】图解 HTTP协议/IIS 原理及ASP.NET运行机制浅析
    【转】Android 消息机制
    Android-eclipse-NDK&JNI
    【转】大型网站系统架构的演化
    【转】Android开发必知--WebView加载html5实现炫酷引导页面
    【转】Java虚拟机详解----GC算法和种类
    网页中缩略图的意义
    网页开关灯效果
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/11700932.html
Copyright © 2011-2022 走看看