zoukankan      html  css  js  c++  java
  • 计算几何(3)

    1.https://codeforces.com/problemset/problem/793/C 2300的计算几何真恶心啊

    题意:n条射线,问全部到达一个矩形"内部"的时间

    思路:1.如果p1在内部,那就只有一个时间点,如果在外部,射入会有一个或两个时间点.

    2.获得一段时间段后,取交集.

    注意:如果点在边缘,而且射线方向平行与x,y轴,那只会从矩形边缘擦过,输出-1

    还有一个,我是先判断一条直线和边框直线有没有交点,然后判断交点在射线上,再判断交点在线段上.挺麻烦.

    交点在射线上用向量判断同方向,

    const int N = 1e5 + 50;
    const int INF = 0x7fffffff;
    const double eps = 1e-9;
    const double PI = acos(-1);
    
    int sgn(double x) {
    	if(fabs(x) < eps)return 0;
    	else return x<0?-1:1;
    }
    
    struct Point {
    	double x,y;
    	Point() {}
    	Point(double x,double y):x(x),y(y) {}
    	Point operator + (Point B) {
    		return Point(x+B.x,y+B.y);
    	}
    	Point operator - (Point B) {
    		return Point(x-B.x,y-B.y);
    	}
    	Point operator /(double k) {
    		return Point(x/k,y/k);
    	}
    	bool operator == (Point B) {
    		return x == B.x && y == B.y;
    	}
    };
    
    struct Line {
    	Point p1,p2;//线上的两个点
    	Line() {}
    	Line(Point p1,Point p2):p1(p1),p2(p2) {}
    
    };
    
    
    double Distance(Point A,Point B) {
    	return hypot(A.x-B.x,A.y-B.y);
    //	return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);
    }
    
    double Cross(Point a,Point b) {
    	return a.x*b.y-a.y*b.x;
    }
    
    typedef  Point Vector;
    
    double Dot(Vector A,Vector B) {
    	return A.x*B.x + A.y*B.y;   //点积
    }
    
    
    //点和直线关系:1 在左侧;2 在右侧;0 在直线上
    int Point_line_relation(Point p,Line v) {
    	int c = sgn(Cross(p-v.p1,v.p2-v.p1));
    	if(c < 0)return 1; //1:p在v的左边
    	if(c > 0)return 2; //2:p在v的右边
    	return 0; //0:p在v上
    }
    
    
    //两直线关系:0 平行,1 重合,2 相交
    int Line_relation(Line v1, Line v2) {
    	if(sgn(Cross(v1.p2-v1.p1,v2.p2-v2.p1)) == 0) {
    		if(Point_line_relation(v1.p1,v2)==0) return 1;//1 重合
    		else return 0;//0 平行
    	}
    	return 2; //2 相交
    }
    
    
    //求两直线ab和cd的交点
    //调用前要保证两直线不平行或重合
    Point Cross_point(Point a,Point b,Point c,Point d) { //Line1:ab, Line2:cd
    	double s1 = Cross(b-a,c-a);
    	double s2 = Cross(b-a,d-a); //叉积有正负
    	return Point(c.x*s2-d.x*s1,c.y*s2-d.y*s1)/(s2-s1);
    }
    
    
    // 点和线段的关系:0 点p不在线段v上;1 点p在线段v上。
    bool Point_on_seg(Point p, Line v) {
    	return sgn(Cross(p-v.p1, v.p2-v.p1)) == 0 && sgn(Dot(p - v.p1,p- v.p2)) <=0;
    }
    
    bool Point_on_sx(Point a,Line p) {
    	if((a.x-p.p1.x)*(p.p2.x-p.p1.x) < 0)return false;
    	if((a.y-p.p1.y)*(p.p2.y-p.p1.y) < 0)return false;
    	return true;
    }
    
    
    
    int n;
    Point A,B,p[N];
    Line l[5];
    Line x[N];
    double dis[N][2];
    int tot=0;
    
    void work() {
    	scanf("%d",&n);
    	scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y);
    	l[0] = Line(Point(A.x,A.y),Point(B.x,A.y));
    	l[1] = Line(Point(B.x,A.y),Point(B.x,B.y));
    	l[2] = Line(Point(B.x,B.y),Point(A.x,B.y));
    	l[3] = Line(Point(A.x,B.y),Point(A.x,A.y));
    	for(int i=0; i<n; i++) {
    		double nx,ny;
    		scanf("%lf%lf%lf%lf",&p[i].x,&p[i].y,&nx,&ny);
    		x[i] = Line(p[i],p[i]+Point(nx,ny));
    	}
    
    	int f=1;
    
    	for(int i=0; i<n; i++) {
    		//判断从边缘擦过的情况
    		if(p[i].x == A.x || p[i].x == B.x || p[i].y == A.y || p[i].y == B.y) {
    			if(sgn(x[i].p2.x-x[i].p1.x) == 0 || sgn(x[i].p2.y-x[i].p1.y) == 0) {
    				f=0;
    				break;
    			}
    		}
    		tot=0;
    		//记录两个时间点
    		for(int j=0; j<4; j++) {
    			if(Line_relation(x[i],l[j]) == 2 ) {
    				Point z = Cross_point(x[i].p1,x[i].p2,l[j].p1,l[j].p2);
    				if(Point_on_sx(z,x[i]) && Point_on_seg(z,l[j])) {  //点在射线上
    					double dd = Distance(p[i],z);
    					//可能存在经过三条边(经过一个顶点)甚至两个顶点...要特判
    					if(tot == 0 || (tot == 1 && fabs(dis[i][0] - dd) > eps) ||
    					        (tot == 2 && fabs(dis[i][0] - dd) > eps && fabs(dis[i][1]-dd)>eps))
    						dis[i][tot++] = dd;
    				}
    			}
    		}
    		int ok = 0;
    		//如果在内部,特殊处理
    		if(p[i].x >= A.x && p[i].x <= B.x && p[i].y >= A.y && p[i].y <= B.y) {
    			if(tot != 2) {
    				tot = 2;
    				ok = 1;
    				dis[i][1] = dis[i][0];
    				dis[i][0] = 0.0;
    			}
    		}
    
    		//不在内部而且有两个交点在同一点 -> 经过一个矩形顶点
    		if(tot != 2 || (!ok && fabs(dis[i][0] - dis[i][1]) < eps)) {
    			f = 0;
    			break;
    		}
    		if(dis[i][0] > dis[i][1])swap(dis[i][0],dis[i][1]);
    	}
    
    	if(f == 0)printf("-1
    ");
    	else {
    		double l=0,r=100000000;
    		for(int i=0; i<n; i++) {
    			l = max(l,dis[i][0]/Distance(x[i].p1,x[i].p2));
    			r = min(r,dis[i][1]/Distance(x[i].p1,x[i].p2));
    		}
    		if(l >= r ) printf("-1
    ");
    		else {
    			printf("%.8f
    ",l);
    		}
    	}
    }
    
  • 相关阅读:
    【原创】Jquery.Greybox.js(Jquery框架下的Greybox源代码)
    【超级原创】截至2009年10月20日双色球中奖号码前500期统计
    ASP.NET C#动态生成html页面
    【原创】JS判断浏览器类型
    【原创】用SQL语句删除重复记录的方法总结
    【原创】 ASP.NET C#反射简单实例应用
    【原创】UpdatePanel 中文乱码的终极解决方案(非常完美)
    【原创】ASP.NET C# 盗取中国银行汇率表
    【原创】ASP.NET 小偷模块(功能罕见)
    ASP.NET C# 货币转换函数 中文大写金额 英文金额
  • 原文地址:https://www.cnblogs.com/LaiYiC/p/15033765.html
Copyright © 2011-2022 走看看