[NOI2009] 描边

题目描述

小 Z 是一位杰出的数学家。聪明的他特别喜欢研究一些数学小问题。

有一天,他在一张纸上选择了 n 个点,并用铅笔将它们两两连接起来,构成 (�−1)22n(n−1)​ 条线段。由于铅笔很细,可以认为这些线段的宽度为 。

望着这些线段,小 Z 陷入了冥想中。他认为这些线段中的一部分比较重要,需要进行强调。因此小 Z 拿出了毛笔,将它们重新进行了描边。毛笔画在纸上,会形成一个半径为 �r 的圆。在对一条线段进行描边时,毛笔的中心(即圆心)将从线段的一个端点开始,沿着该线段描向另一个端点。下图即为在一张 44 个点的图中,对其中一条线段进行描边强调后的情况。

[NOI2009] 描边_第1张图片

现在,小 Z 非常想知道在描边之后纸面上共有多大面积的区域被强调,你能帮助他解答这个问题么?

输入格式

本题是一道提交答案型试题,所有的输入文件 path1.in ∼∼ path10.in 已在相应目录下。

输入文件请点击 这里 下载。

输入文件的第一行为一个正整数 �n,表示选择的点的数目。

第二行至第 �+1n+1 行,其中:第 �+1i+1 行中为两个实数 ��,��xi​,yi​,表示点 �i 的坐标为 (��,��)(xi​,yi​)。

第 �+2n+2 行为一个正整数 �m,表示小 Z 认为比较重要的线段的条数。

第 �+3n+3 行至第 �+�+2n+m+2 行,每行有两个正整数 �,�a,b,表示一条线段。其中 �,�a,b 两个数分别表示该线段的两个端点的编号。

第 �+�+3n+m+3 行中为一个实数 �r,表示毛笔在纸上形成的圆的半径。

第 �+�+4n+m+4 行中为四个实数 �1,�2,�3,�4p1​,p2​,p3​,p4​,即评分使用的参数。

输出格式

输出文件 path*.out 仅一行一个数,即为描边后被强调区域的总面积。

输入输出样例

输入 #1复制

2
1 1
1 2
1
1 2
1
0.00001 0.001 0.1 1

输出 #1复制

5.1415927

说明/提示

每个测试点单独评分。

本题设有 44 个评分参数 �1,�2,�3,�4p1​,p2​,p3​,p4​(�1<�2<�3<�4p1​

你的得分将按照如下规则给出:

  • 若你的答案与标准答案相差不超过 �1p1​,则该测试点你将得到满分;
  • 否则,若你的答案与标准答案相差不超过 �2p2​,则你将得到该测试点 70%70% 的分数;
  • 否则,若你的答案与标准答案相差不超过 �3p3​,则你将得到该测试点 40%40% 的分数;
  • 否则,若你的答案与标准答案相差不超过 �4p4​,则你将得到该测试点 10%10% 的分数;
  • 否则,该测试点你的得分为 00。

#include
using namespace std;
typedef long long ll;
typedef long double ld;
const int N=2505;
const ld eps=1e-9;
int n,m,u[N],v[N],cnt;
ld r,mxx=-1e9,mix=1e9,mxy=-1e9,miy=1e9;
ld ans;
struct aa
{
	ld x,y;
	aa operator +(const aa &b)const{return aa{x+b.x,y+b.y};}
	aa operator -(const aa &b)const{return aa{x-b.x,y-b.y};}
	aa operator *(const ld &b)const{return aa{x*b,y*b};}
	ld operator ^(const aa &b)const{return x*b.y-y*b.x;}
	ld operator *(const aa &b)const{return x*b.x+y*b.y;}
	ld dis() {return sqrt(x*x+y*y);}
}dt[N];
int sgn(ld x) {return (x>eps)-(x<-eps);}
struct bb
{
	ld ps;
	int fl;
	bool operator <(const bb &b)const{return sgn(ps-b.ps)? psb.fl;}
}Ln[N+N];
bool in(aa s,aa t,aa x)
{
	ld lp=((x-s)^(t-s));
	if(sgn(lp)>0) swap(s,t);
	else lp=-lp;
	aa la=t-s,lb=la;
	swap(lb.x,lb.y),lb.x=-lb.x;
	if(sgn((x-s)^lb)>=0&&sgn((x-t)^lb)<=0) return lp/la.dis()<=r;
	return min((x-s).dis(),(x-t).dis())<=r;
}
int main()
{
	freopen("path10.in","r",stdin);
	freopen("path10.out","w",stdout); 
	int i,j;
	for(cin>>n,i=1;i<=n;i++)
		cin>>dt[i].x>>dt[i].y,mxx=max(mxx,dt[i].x),mix=min(mix,dt[i].x),
		mxy=max(mxy,dt[i].y),miy=min(miy,dt[i].y);
	for(cin>>m,i=1;i<=m;i++) cin>>u[i]>>v[i];
	cin>>r,mix-=r,mxx+=r,miy-=r,mxy+=r;
	ld px=(mxx-mix)/10000000.0;
	int Cl=0;
	for(ld X1=mix+px/2,X;X1X&&min(dt[u[i]].x,dt[v[i]].x)-rfabs(dt[v[i]].x-X)) swap(u[i],v[i]);
				if(fabs(dt[u[i]].x-X)eps)
					{
						mid=(pl+pr)/2;
						if(in(dt[u[i]],dt[v[i]],aa{X,st+mid})) pl=mid;
						else pr=mid;
					}
					Ln[++cnt]=bb{st+(pl+pr)/2,-1},pl=0,pr=st-miy;
					while(pr-pl>eps)
					{
						mid=(pl+pr)/2;
						if(in(dt[u[i]],dt[v[i]],aa{X,st-mid})) pl=mid;
						else pr=mid;
					}
					Ln[++cnt]=bb{st-(pl+pr)/2,1};
				}
				else
				{
					if(dt[u[i]].x>dt[v[i]].x) swap(u[i],v[i]);
					aa lp=dt[v[i]]-dt[u[i]];
					ld la=dt[u[i]].y+lp.y*(X-dt[u[i]].x)/(dt[v[i]].x-dt[u[i]].x),lb=r*lp.dis()/(dt[v[i]].x-dt[u[i]].x);
					Ln[++cnt]=bb{la-lb,1},Ln[++cnt]=bb{la+lb,-1};
				}
			}
		sort(Ln+1,Ln+cnt+1);
		for(i=1,j=0;i<=cnt;i++)
			ans+=(!!j)*(Ln[i].ps-Ln[i-1].ps)*px,j+=Ln[i].fl;
	}
	printf("%.9Lf",ans);
	return 0;
}

 

你可能感兴趣的:(c++简介,c++,算法)