BZOJ 1845 CQOI 2005 三角形面积并 扫描线

题目大意:给出一些三角形,求这些三角形面积的并。

思路:应该可以辛普森积分,但是应该会很麻烦。。

以前扫描线就写过矩形的用数据结构维护的那种,和计算几何不占边,这次才是好好写了一次正宗的扫描线。不得不说这个算法还是很靠谱的。

其实这个思路不仅限于三角形面积的并,所有凸多边形的面积并应该都可以解决。

对于任意由线段组成的图形,对这个图形进行多次的划分,总可以将这个图形划分成梯形,面积也很好计算。那么按照什么划分呢?将所有三角形的边都求交点,不难发现,以这些点为划分依据的话,相邻两点之间一定是一个或者多个梯形或三角形(可以看成是特殊的梯形)。因为相邻两点之间不存在其他拐点。这样就把整个图划分成了很多梯形的和。

由于每次区间中的不一定是一个梯形,这些梯形的中位线总长需要将x=x‘这条线与所有三角形相交的区域求交,然后再计算。这就可以随便乱搞了,反正扫描线的总体时间复杂度是O(n^3)的,别比这个大就行了。这就是扫描线的基本思路。

有一些细节,刚开始写处处碰壁。。。

比如按照横坐标划分,就会有数据中有的三角形的边垂直于x轴,不好计算上底和下底,就不好计算面积了。可以转化一下,我们只需要计算这个梯形的中位线长。一定不会有一条边在梯形的中位线上,所以就避免了这个问题。

剩下的就可以尽情的乱搞了。。。

CODE:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define MAX 110
#define EPS 1e-7
using namespace std;
#define DCMP(a) (fabs(a) < EPS)
#define INRANGE(l,r,c) ((c) <= (r) && (c) >= (l))

struct Point{
	double x,y;

	void Read() {
		scanf("%lf%lf",&x,&y);
	}
	Point(double _,double __):x(_),y(__) {}
	Point() {}
	bool operator <(const Point &a)const {
		return x < a.x;
	}
	Point operator +(const Point &a)const {
		return Point(x + a.x,y + a.y);
	}
	Point operator -(const Point &a)const {
		return Point(x - a.x,y - a.y);
	}
	Point operator *(double a)const {
		return Point(x * a,y * a);
	}
}a,b,c,point[MAX * MAX * 10];
int points;

struct Line{
	Point p,v;
	double alpha;

	Line(Point _,Point __):p(_),v(__) {
		alpha = atan2(v.y,v.x);
	}
	Line() {}
}line[MAX << 2];
int lines;

struct Interval{
	double l,r;

	Interval(double _,double __):l(_),r(__) {
		if(l > r)	swap(l,r);
	}
	Interval() {}
	bool operator <(const Interval &a)const {
		if(l == a.l)	return r < a.r;
		return l < a.l;
	}
}interval[MAX];
int intervals;

inline double Cross(const Point &p1,const Point &p2)
{
	return p1.x * p2.y - p2.x * p1.y;
}

inline Point GetIntersection(const Line &a,const Line &b)
{
	Point u = a.p - b.p;
	double temp = Cross(b.v,u) / Cross(a.v,b.v);
	return a.p + a.v * temp;
}

inline void Sort(double &y1,double &y2,double &y3)
{
	double arr[] = {y1,y2,y3};
	sort(arr,arr + 3);
	y1 = arr[0],y2 = arr[1],y3 = arr[2];
}

struct Triangle{
	Line _a,b,c;
	Point p1,p2,p3;
	double w,s,a,d;

	void MakeTriangle(const Point &p,const Point &_p,const Point &__p) {
		p1 = p,p2 = _p,p3 = __p;
		_a = line[++lines] = Line(p1,p2 - p1);
		b = line[++lines] = Line(p2,p3 - p2);
		c = line[++lines] = Line(p3,p1 - p3);
		w = max(p1.y,max(p2.y,p3.y));
		s = min(p1.y,min(p2.y,p3.y));
		a = min(p1.x,min(p2.x,p3.x));
		d = max(p1.x,max(p2.x,p3.x));
	}
	void GetInterval(double x) {
		if(!INRANGE(a,d,x))	return ;
		Line l(Point(x,0),Point(0,1));
		Point pa = GetIntersection(l,_a),pb = GetIntersection(l,b),pc = GetIntersection(l,c);
		double x1 = p1.x,x2 = p2.x,x3 = p3.x;
		if((INRANGE(x1,x2,x) || INRANGE(x2,x1,x)) && (INRANGE(x1,x3,x) || INRANGE(x3,x1,x)))	interval[++intervals] = Interval(pa.y,pc.y);
		else if((INRANGE(x1,x2,x) || INRANGE(x2,x1,x)) && (INRANGE(x2,x3,x) || INRANGE(x3,x2,x)))	interval[++intervals] = Interval(pa.y,pb.y);
		else	interval[++intervals] = Interval(pb.y,pc.y);
	}
}triangle[MAX];

int cnt;

int main()
{
	cin >> cnt;
	for(int i = 1; i <= cnt; ++i) {
		a.Read();
		b.Read();
		c.Read();
		triangle[i].MakeTriangle(a,b,c);
	}
	for(int i = 1; i <= lines; ++i)
		for(int j = 1; j <= lines; ++j)
			if(!DCMP(Cross(line[i].v,line[j].v)))
				point[++points] = GetIntersection(line[i],line[j]);
	sort(point + 1,point + points + 1);
	double area = .0;
	for(int i = 2; i <= points; ++i) {
		if(DCMP(point[i].x - point[i - 1].x))	continue;
		static double last_x = point[1].x;
		double now = .0,x = (point[i].x + last_x) / 2;
		intervals = 0;
		for(int j = 1; j <= cnt; ++j)
			triangle[j].GetInterval(x);
		sort(interval + 1,interval + intervals + 1);
		for(int j = 1; j <= intervals; ++j) {
			double l = interval[j].l,r = interval[j].r;
			int k;
			for(k = j + 1; k <= intervals; ++k) {
				if(interval[k].l <= r)	r = max(r,interval[k].r);
				else	break;
			}
			now += r - l;
			j = k - 1;
		}
		area += now * (point[i].x - last_x);
		last_x = point[i].x;
	}
	cout << fixed << setprecision(2) << area - EPS << endl;
	return 0;
}

时间: 2024-11-05 15:57:50

BZOJ 1845 CQOI 2005 三角形面积并 扫描线的相关文章

bzoj 1845: [Cqoi2005] 三角形面积并 扫描线

1845: [Cqoi2005] 三角形面积并 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 848  Solved: 206[Submit][Status][Discuss] Description 给出n个三角形,求它们并的面积. Input 第一行为n(N < = 100), 即三角形的个数 以下n行,每行6个整数x1, y1, x2, y2, x3, y3,代表三角形的顶点坐标.坐标均为不超过10 ^ 6的实数,输入数据保留1位小数 Outp

BZOJ 1845: [Cqoi2005] 三角形面积并 [计算几何 扫描线]

1845: [Cqoi2005] 三角形面积并 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 1151  Solved: 313[Submit][Status][Discuss] Description 给出n个三角形,求它们并的面积. Input 第一行为n(N < = 100), 即三角形的个数 以下n行,每行6个整数x1, y1, x2, y2, x3, y3,代表三角形的顶点坐标.坐标均为不超过10 ^ 6的实数,输入数据保留1位小数 Out

bzoj 1845: [Cqoi2005] 三角形面积并

https://www.lydsy.com/JudgeOnline/problem.php?id=1845 将所有三角形的端点.交点按x坐标排序,从左往右扫描线 每相邻两根扫描线a和b之间的形状是若干个不相交的梯形或三角形 用公式:中位线长度*高 计算面积 高就是两条扫描线之间的距离 中位线,计算x=(xa+xb)/2 被覆盖了多长即可 因为已将三角形端点考虑在内,所以线段相交只需要考虑规范相交即可 直接套lrj的板子 #include<cmath> #include<cstdio>

BZOJ1845CQOI2005三角形面积并

1845: [Cqoi2005] 三角形面积并 Description 给出n个三角形,求它们并的面积. Input 第一行为n(N < = 100), 即三角形的个数 以下n行,每行6个整数x1, y1, x2, y2, x3, y3,代表三角形的顶点坐标.坐标均为不超过10 ^ 6的实数,输入数据保留1位小数 Output 输出并的面积u, 保留两位小数 Sample Input 2 0.0 0.0 2.0 0.0 1.0 1.0 1.0 0.0 3.0 0.0 2.0 1.0 Sample

叉乘、快速排斥与跨立实验及求取三角形面积

<pre name="code" class="cpp">叉乘 (一)判断方向 (二)判断线段相交 (三)求三角形面积 (一)判断方向 叉乘的性质如下: (1). P x Q > 0; 表示P在Q的顺时针方向; (2). p x Q < 0; 表示P在Q的逆时针方向; (3). P x Q = 0; 表示P和Q是共线的 P(x1,y1),Q(x2,y2), P*Q=x1y2-x2y1 判断结果三种状态 模版为: struct point {

三角形面积

如图1所示.图中的所有小方格面积都是1. 那么,图中的三角形面积应该是多少呢? 请填写三角形的面积.不要填写任何多余内容或说明性文字.

三角形面积(海伦公式)

来自:http://www.oschina.net/code/snippet_149523_14180 描述 给你三个点,表示一个三角形的三个顶点,现你的任务是求出该三角形的面积 输入 每行是一组测试数据,有6个整数x1,y1,x2,y2,x3,y3分别表示三个点的横纵坐标.(坐标值都在0到10000之间)输入0 0 0 0 0 0表示输入结束测试数据不超过10000组 输出 输出这三个点所代表的三角形的面积,结果精确到小数点后1位(即使是整数也要输出一位小数位) 样例输入 0 0 1 1 1

rwkj 1363 正方形 长方形 三角形面积

C++:重载函数2(计算面积)时间限制(普通/Java):1000MS/3000MS 运行内存限制:65536KByte总提交:370 测试通过:241 描述 定义重载函数area(),分别计算正方形.长方形和三角形的面积. 输入 共计有3行. 第1行有一个实数,为正方形的边长: 第2行有二个实数,为长方形的两条边长: 第3行有三个实数,为三角形的三边长. 输出 正方形.长方形和三角形的面积(保留3位小数). 样例输入 3.54.2 5.623.0 4.0 5.0 样例输出 12.25023.6

Java入门:基础算法之计算三角形面积

本部分介绍如何计算三角形面积. /** * @author: 理工云课堂 * @description: 程序计算三角形的面积.三角形的底和高由用户输入 */ import java.util.Scanner; class AreaTriangleDemo { public static void main(String args[]) { Scanner scanner = new Scanner(System.in); System.out.println("Enter the width