博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ】1043: [HAOI2008]下落的圆盘(计算几何基础+贪心)
阅读量:5894 次
发布时间:2019-06-19

本文共 3277 字,大约阅读时间需要 10 分钟。

唯一让我不会的就是怎么求圆的周长并QAAQ...

然后发现好神!我们可以将圆弧变成$[0, 2 \pi ]$的直线!

然后一定要注意!起点是$(1, 0)$(单位圆)

首先学了余弦定理...

在三角形ABC中

$$cos A=\frac{|AB|^2+|AC|^2-|BC|^2}{2|AB| |AC|}$$

证明很简单...

$$

\begin{align}
|{BC}|^2 & = \vec{BC} \cdot \vec{BC} \\
& = (\vec{AC}-\vec{AB}) \cdot (\vec{AC}-\vec{AB}) \\
& = | \vec{AC} |^2 + | \vec{AB} |^2 - 2|AC| |AB|cos A \\
\end{align}
$$
移项一下就是:
$$cos A=\frac{|AB|^2+|AC|^2-|BC|^2}{2|AB| |AC|}$$

一开始看了题解后想了一下就写了,求圆的交点..交点的极角...然后离散到的是$[0, \pi ]$的直线...然后喜闻乐见的悲剧了...

一定要知道!极角虽然是算出来了!但是同一个位置可能有两种角啊....为嘛我当时脑残...${\alpha + 2k \pi}$啊....

所以要区分一下..当极角<0时,先加上$2\pi$,然后如果原来极角小的比原来极角大的角要大了,说明它要分成两段来计算,即$[0, r]$, $[l, 2\pi ]$

然后将线段排序贪心取即可..(其实可以直接差分啊QAQ我是sb...

#include 
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;typedef long long ll;#define rep(i, n) for(int i=0; i<(n); ++i)#define for1(i,a,n) for(int i=(a);i<=(n);++i)#define for2(i,a,n) for(int i=(a);i<(n);++i)#define for3(i,a,n) for(int i=(a);i>=(n);--i)#define for4(i,a,n) for(int i=(a);i>(n);--i)#define CC(i,a) memset(i,a,sizeof(i))#define read(a) a=getint()#define print(a) printf("%d", a)#define dbg(x) cout << (#x) << " = " << (x) << endl#define error(x) (!(x)?puts("error"):0)#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }const double PI=acos(-1), eps=1e-6;int dcmp(double x) { return abs(x)
<0?-1:1); }struct ipt { double x, y; ipt(double _x=0, double _y=0) : x(_x), y(_y) {} };struct icir { ipt x; double r; };typedef ipt ivt;ivt operator- (ipt &a, ipt &b) { return ivt(a.x-b.x, a.y-b.y); }double iangle(ivt v) { return atan2(v.y, v.x); }double sqr(double x) { return x*x; }double dis(ipt &a, ipt &b) { return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y)); }bool getCC(icir &a, icir &b, double &ang1, double &ang2) { static double d, ang; d=dis(a.x, b.x); if(dcmp(d)==0) return false; if(dcmp(a.r+b.r-d)<=0) return false; if(dcmp(a.r-b.r-d)>=0) return false; ang=iangle(b.x-a.x); double da=acos((sqr(d)+sqr(a.r)-sqr(b.r))/a.r/d/2); ang1=ang-da; //dbg(da); ang2=ang+da; return true;}const int N=1005;int n;icir a[N];struct dat { double l, r; }line[N*2];bool cmp(const dat &a, const dat &b) { return a.l==b.l?a.r>b.r:a.l
=0) return 0; } //puts("here"); for1(i, now+1, n) { if(getCC(a[now], a[i], ang1, ang2)==false) continue; if(ang1<0) ang1+=PI*2; if(ang2<0) ang2+=PI*2; if(dcmp(ang1-ang2)>0) { ++ln; line[ln].l=0; line[ln].r=ang2; ++ln; line[ln].l=ang1; line[ln].r=PI*2; } else { ++ln; line[ln].l=ang1; line[ln].r=ang2; } } sort(line+1, line+1+ln, cmp); double w=0, mx=0; for1(i, 1, ln) { if(dcmp(mx-line[i].r)>=0) continue; mx=max(mx, line[i].l); w+=line[i].r-mx; mx=max(mx, line[i].r); } return a[now].r*(PI*2-w);}int main() { read(n); for1(i, 1, n) scanf("%lf%lf%lf", &a[i].r, &a[i].x.x, &a[i].x.y); double ans=0; for1(i, 1, n) ans+=work(i); printf("%.3f\n", ans); return 0;}

  

 


 

 

Description

有n个圆盘从天而降,后面落下的可以盖住前面的。求最后形成的封闭区域的周长。看下面这副图, 所有的红色线条的总长度即为所求. 

Input

n ri xi y1 ... rn xn yn

Output

最后的周长,保留三位小数

Sample Input

2
1 0 0
1 1 0

Sample Output

10.472

HINT

 

数据规模

n<=1000

 

Source

 

 

 

转载地址:http://rkisx.baihongyu.com/

你可能感兴趣的文章
css的border的solid
查看>>
div+css实现window xp桌面图标布局(至上而下从左往右)
查看>>
0-1 背包问题
查看>>
运行Maven是报错:No goals have been specified for this build
查看>>
Haskell 差点儿无痛苦上手指南
查看>>
[MODx] Build a CMP (Custom manager page) using MIGX in MODX 2.3 -- 1
查看>>
NTP 服务器配置
查看>>
jQuery自动完成点击html元素
查看>>
[算法]基于分区最近点算法的二维平面
查看>>
linux在文件打包和压缩
查看>>
webpack多页应用架构系列(七):开发环境、生产环境傻傻分不清楚?
查看>>
构建 iOS 界面:子类化 Views
查看>>
笨办法学C 练习1:启用编译器
查看>>
树的总结--树的性质(树的深度) leetcode
查看>>
在 IIS 下添加 FLV 类型文件的支持
查看>>
穿过任意防火墙NAT的远程控制软件TeamViewer
查看>>
nagios短信报警(飞信fetion20080522004-linrh4)
查看>>
【Android游戏开发之六】在SurfaceView中添加组件!!!!并且相互交互数据!!!!...
查看>>
异常处理汇总-开发工具
查看>>
[LeetCode] Excel Sheet Column Number 求Excel表列序号
查看>>