BZOJ 1043 HAOI 2008 下落的圆盘 计算几何

题目大意:给出一些圆盘,他们按照时间顺序相互覆盖,问最后的到的图形的可见圆周的周长是多少。

前言:円盘反对!让我们一起团结起来!赶走円盘!

思路:对于每一个圆盘,只要扫描在它后面出现的圆与它交的部分的并,总周长-相交的并就是剩下能看见的圆周的长度,然后累加到答案中。

对于两个圆的交,我们可以用一个有序数对(x,y)以弧度为单位来表示,这样所有的xy都在0~2π区间之内。求角度就利用余弦定理,见下图:

∠EAC就是我们要求的角。由于我们知道|AE|和|EC|分别是两个圆的半径,|AC|是圆心的距离,边都知道了就可以用余弦定理来求解任意一个角了。知道了这个角的大小,用向量(A->C)的极角加上∠EAC就是E点所代表的位置,减去∠EAC就是F点所代表的位置。这样就可以表示出两圆相交的区间了。

但是我们要保证所有的端点都在[0,2π]的区间之内,所以如果有加爆了或者减爆了的区间,要把他们分成两个区间。最后一步就是排序,然后求区间的并,计算可见的圆周长。

CODE:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define PI acos(-1.0)
#define MAX 1010
using namespace std;

struct Point{
	double x,y;

	Point(double _ = .0,double __ = .0):x(_),y(__) {}
	Point operator -(const Point &a)const {
		return Point(x - a.x,y - a.y);
	}
	void Read() {
		scanf("%lf%lf",&x,&y);
	}
};
struct Circle{
	Point o;
	double r;

	void Read() {
		scanf("%lf",&r);
		o.Read();
	}
}circle[MAX];

struct Interval{
	double st,ed;

	Interval(double _ = .0,double __ = .0):st(_),ed(__) {}
	bool operator <(const Interval &a)const {
		if(st == a.st)	return ed < a.ed;
		return st < a.st;
	}
}interval[MAX];

int circles,cnt;
double ans;

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

inline void InsertInterval(const Circle &a,const Circle &b)
{
	double dis = Calc(a.o,b.o);
	if(dis > a.r + b.r)	return ;
	if(dis < a.r - b.r)	return ;
	if(dis < b.r - a.r) {
		interval[++cnt] = Interval(.0,2.0 * PI);
		return ;
	}
	Point u = b.o - a.o;
	double alpha = atan2(u.y,u.x) + PI;
	double detla = acos((a.r * a.r + dis * dis - b.r * b.r) / (2.0 * a.r * dis));
	if(alpha - detla < 0) {
		interval[++cnt] = Interval(alpha - detla + 2.0 * PI,2.0 * PI);
		interval[++cnt] = Interval(0,alpha + detla);
	}
	else if(alpha + detla > 2.0 * PI) {
		interval[++cnt] = Interval(alpha - detla,2.0 * PI);
		interval[++cnt] = Interval(0,alpha + detla - 2.0 * PI);
	}
	else
		interval[++cnt] = Interval(alpha - detla,alpha + detla);
}

int main()
{
	cin >> circles;
	for(int i = 1; i <= circles; ++i)
		circle[i].Read();
	for(int i = circles; i; --i) {
		cnt = 0;
		for(int j = i + 1; j <= circles; ++j)
			InsertInterval(circle[i],circle[j]);
		sort(interval + 1,interval + cnt + 1);
		double start = .0,end = .0;
		double length = .0;
		for(int j = 1; j <= cnt; ++j)
			if(interval[j].st > end)
				length += end - start,start = interval[j].st,end = interval[j].ed;
			else
				end = max(end,interval[j].ed);
		length += end - start;
		length = PI * 2.0 - length;
		ans += length * circle[i].r;
	}
	cout << fixed << setprecision(3) << ans << endl;
	return 0;
}
时间: 2024-11-05 22:44:02

BZOJ 1043 HAOI 2008 下落的圆盘 计算几何的相关文章

bzoj1043[HAOI2008]下落的圆盘 计算几何

1043: [HAOI2008]下落的圆盘 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1598  Solved: 676[Submit][Status][Discuss] Description 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红色线条的总长度即为所求.  Input 第一行为1个整数n,N<=1000接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标

BZOJ 1043 HAOI2008 下落的圆盘 计算几何

题目大意:n个圆盘依次下落.求终于能看到的轮廓线面积 円盘反对! 让我们一起团结起来! 赶走円盘! 咳咳.非常神的一道题 今天去看了题解和白书才搞出来-- 首先我们倒着做 对于每一个圆盘处理出在它之后落下的圆盘和它的覆盖区间 然后求一个区间并就能算出这个圆盘的可见弧长 然后就是相交部分怎么求的问题了 首先两个圆必须相交 然后作圆心1到圆心2的向量 用atan2求出极角 然后利用余弦定理求出两个交点和圆心连线的夹角就可以 注意区间不在[0,2π]的部分要切割成还有一个区间 处理起来事实上不是非常麻

【bzoj1043】[HAOI2008]下落的圆盘 计算几何

题目描述 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红色线条的总长度即为所求. 输入 第一行为1个整数n,N<=1000接下来n行每行3个实数,ri,xi,yi,表示下落时第i个圆盘的半径和圆心坐标. 输出 最后的周长,保留三位小数 样例输入 2 1 0 0 1 1 0 样例输出 10.472 题解 计算几何 考虑从下到上的每一个圆,它被其它的圆覆盖了多少.即考虑它被覆盖了多少弧度. 考虑两个圆,如果相离则不覆盖,内含判断一下包含关系. 如果

[BZOJ 1054][HAOI 2008]移动玩具(BFS+判重)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1054 真是水题,感谢HAOI送的福利样例23333 裸BFS,用string做判重,会八数码就会这题. 注意由于队列中状态数很多,一定要把队列的数组开大点!!! #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <

[BZOJ 1042][HAOI 2008]硬币购物(背包+容斥原理)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1042 刚开始搞容斥原理,还很有点吃力,我太弱了... 首先用被类似于背包的DP进行预处理,假设每种硬币个数无限制,求出f[i]=凑出面值i的方案总数. 但是实际上题目中每种硬币个数是有限制的,设四种硬币分别是a.b.c.d,则凑出面值S的方案中超出限制的方案数=a超出限制的方案数+b超出限制的方案数+c超出限制的方案数+d超出限制的方案数-a和b都超出限制的方案数-a和c都超出限

BZOJ 1042 HAOI 2008 硬币购物 容斥原理

题目大意:给出4个硬币的价值和个数限制,求有多少种方法凑成S块钱. 思路:很巧妙的一种想法,用到了4这个非常小的数字.我们可以先不管每个硬币的个数限制,然后跑一次完全背包.之后把不符合的情况去除就行了.方法是,先减去一种硬币超限的数目,然后加上两种硬币超限的数目,然后减去三种硬币超限的数目,然后加上四种硬币超限的个数.当然代码就很丑了.. CODE: #include <cstdio> #include <cstring> #include <iostream> #in

【BZOJ1043】【HAOI2008】下落的圆盘 计算几何

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46564199"); } 题解: 给每个圆求一下: 1. 它是不是被之后的某圆整体覆盖. 2. 它的圆周上有哪些弧段被覆盖了. 然后对于每个圆求一下还剩多少周长即可. 上述的"2."可以用圆的圆心角

BZOJ 1007 HNOI 2008 水平可见直线 计算几何+栈

题目大意:给出一些笛卡尔系中的一些直线,问从(0,+∞)向下看时能看到哪些直线. 思路:半平面交可做,但是显然用不上.类似于求凸包的思想,维护一个栈.先将所有直线按照k值排序,然后挨个压进去,遇到有前一个交点被挡住的话就先弹栈. 比较闹心的是去重.我的方法是压栈之前先去重,然后在处理. CODE: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #includ

JZYZOJ1502 [haoi2008]下落的圆盘 计算几何 贪心

http://172.20.6.3/Problem_Show.asp?id=1502这种题用了快一天才写出来也是真的辣鸡.主要思路就是计算一下被挡住的弧度然后对弧度进行贪心.最开始比较困扰的是求弧度值及其起始位置的部分,弧度值很好求,位置有点恶心,我的起始位置设置的是圆的十二点方向顺时针到起始位置的弧度值,然后我分了四种情况讨论(因为遮挡的方向有两种不同情况,遮挡部分弧度值与180度的关系又是两种情况),应该是有更简单的方法的,但是我只能想出来这种了... 代码 1 #include<cstdi