zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    随机森林算法参数调优
    BAYES和朴素BAYES
    阿里云 金融接口 token PHP
    PHP mysql 按时间分组 表格table 跨度 rowspan
    MySql按周,按月,按日分组统计数据
    PHP 获取今日、昨日、本周、上周、本月的等等常用的起始时间戳和结束时间戳的时间处理类
    thinkphp5 tp5 会话控制 session 登录 退出 检查检验登录 判断是否应该跳转到上次url
    微信 模板消息
    php 腾讯 地图 api 计算 坐标 两点 距离 微信 网页 WebService API
    php添加http头禁止浏览器缓存
  • 原文地址:https://www.cnblogs.com/rolight/p/3691750.html
Copyright © 2011-2022 走看看