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;
}

  

原文地址:https://www.cnblogs.com/rolight/p/3691750.html