• Poj 2284 That Nice Euler Circuit


    人生第一道正儿八经的计算几何题。。。光消编译错误就弄了老半天,果然是够弱。。

    题意大概是,给你N条线段,它们会构成一个一笔画的图形,给你先线段的顺序就是一笔画的顺序,线段可能相交但是不会重合

    问你最后那个图形可以将平面分成多少个区域(包括有穷区域和无穷区域)

    显然这里可以利用欧拉定理来求解,即平面上的点数+面数=边数+2

    那么问题就转化为求最后的图形有多少个点和多少条边了。

    大体思路是,通过枚举线段来求出所有线段的交点,加上原有题目告诉你的所有线段的起点和终点,可以求得图中所有的点的数量。

    但是因为有可能出现三点共线的情况,这样会导致多余的点的出现,因此求出所有的点之后对点集做一次去重处理,可以利用STL里面的unique函数,非常的方便

    然后枚举每一个新增的交点,如果这个交点在一个线段之间,那么就会导致一条新边的产生。

    由此就完成了边和点的统计

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    
    #define INPUT_FILE "in.txt"
    #define OUTPUT_FILE "out.txt"
    
    using namespace std;
    
    typedef long long LL;
    const int maxn = 400;
    const double eps = 1e-10;
    
    void setfile() {
    	freopen(INPUT_FILE,"r",stdin);
    	freopen(OUTPUT_FILE,"w",stdout);
    }
    
    struct Point {
    	double x,y;
    	Point(double x = 0,double y = 0):x(x),y(y) {
    	}
    };
    
    typedef Point Vector;
    Point v[maxn * maxn];	//顶点
    Point p[maxn];
    
    Vector operator - (Point a,Point b) {
    	return Vector(a.x - b.x,a.y - b.y);
    }
    
    Vector operator * (Vector a,double p) {
    	return Vector(a.x * p,a.y * p);
    }
    
    Vector operator + (Vector a,Vector b) {
    	return Vector(a.x + b.x,a.y + b.y);
    }
    
    double dot(Vector a,Vector b) {
    	return a.x * b.x + a.y * b.y;
    }
    
    int dcmp(double x) {
    	if(fabs(x) < eps) return 0;
    	return x < 0 ? -1 : 1;
    }
    
    bool operator < (Point a,Point b) {
    	return a.x < b.x || (a.x == b.x && a.y < b.y);
    }
    
    double cross(Vector a,Vector b) {
    	return a.x * b.y - a.y * b.x;
    }
    
    bool have_intersection(Point a1,Point a2,Point b1,Point b2) {
    	double c1 = cross(a2 - a1,b1 - a1),c2 = cross(a2 - a1,b2 - a1);
    	double c3 = cross(b2 - b1,a1 - b1),c4 = cross(b2 - b1,a2 - b1);
    	bool ret = (dcmp(c1) * dcmp(c2) < 0) && (dcmp(c3) * dcmp(c4) < 0);
    	return ret;
    }
    
    bool on_segment(Point p,Point a,Point b) {
    	return dcmp(cross(p - a,p - b)) == 0 && dcmp(dot(a - p,b - p)) < 0;
    }
    
    Point get_intersection(Point a1,Point a2,Point b1,Point b2) {
    	Vector v = a2 - a1,w = b2 - b1,u = a1 - b1;
    	double t = cross(w,u) / cross(v,w);
    	return a1 + v * t;
    }
    
    bool operator == (Point a,Point b) {
    	return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;
    }
    
    int main() {
    	int n,kase = 1;
    	while(scanf("%d",&n),n) {
    		for(int i = 0;i < n;i++) {
    			scanf("%lf%lf",&v[i].x,&v[i].y);
    			p[i] = v[i];
    		}
    		int cnt_v = n - 1,cnt_f = 0,cnt_e = n - 1;	
    		n--;		
    		//判断一下给定的线段是否有交点
    		for(int i = 0;i < n;i++) {
    			for(int j = i + 1;j < n;j++) {
    				if(have_intersection(p[i],p[i + 1],p[j],p[j + 1])) {
    					//找到交点了就添加到点集里面
    					v[cnt_v++] = get_intersection(p[i],p[i + 1],p[j],p[j + 1]);
    				}
    			}
    		}
    		//特判三点共线的时候的状态
    		sort(v,v + cnt_v);
    		cnt_v = unique(v,v + cnt_v) - v;
    		//处理因为线段交点而新生成的线段
    		for(int i = 0;i < cnt_v;i++) {
    			for(int j = 0;j < n;j++) {
    				if(on_segment(v[i],p[j],p[j + 1])) {
    					cnt_e++;
    				}
    			}
    		}
    		printf("Case %d: There are %d pieces.
    ",kase++,2 + cnt_e - cnt_v);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    Android应用程序执行流程
    Android的架构与Android应用程序启动流程
    Android开发环境使用工具Eclipse IDE工程目录结构
    MySQL 的 crash-safe 原理解析
    vivo 悟空活动中台
    图解 Promise 实现原理(三)—— Promise 原型方法实现
    领域驱动设计(DDD)实践之路(三):如何设计聚合
    深入浅出开源监控系统Prometheus(上)
    你还应该知道的哈希冲突解决策略
    反应式编程 RxJava 设计原理解析
  • 原文地址:https://www.cnblogs.com/rolight/p/3691750.html
Copyright © 2020-2023  润新知