【2022国赛模拟】多边形——计算几何、二分答案、倍增

好题无链接

题目描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
补充说明:题目虽然说的是凸多边形,但是它其实可以不封闭。也就是说,你可以看成是 m m m 个半平面的交。点到边的距离可以看成到线段,也可以看成到直线,其实无所谓。

题解

大家都知道落榜美术生的梗吧

为什么说看成到线段或直线的距离无所谓呢,是因为不管哪一种距离,每条边到原点的距离最好都相等,否则一定不优。有了这个结论,我们发现原点到直线的垂线一定交于线段上。

首先明白答案具有单调性,然后就可以二分答案了。另外还有一个单调性,即 m m m 越大越优。

考虑怎么进行 c h e c k \rm check check:首先对于一个可行的解,我们可以把每一条直线往一个方向旋转,直到撞到点上。容易证明任何可行解的每条边总可以调整到与点相交,这样一来需要考虑的直线就只有 n n n 条了。
在这里插入图片描述
考虑一个暴力做法,我们枚举一条直线作为起点,然后旋转扫描线,每次顺时针(或逆时针)贪心地找到第一条满足没有节点出现在两直线中间范围内的直线作为下一条。(如上图,假设当前直线为 a a a,那么 b b b 是要找的下一条直线, c c c d d d 都不是)
直到总共找到 m + 1 m+1 m+1 条直线(包括起点),然后判断扫描线有没有扫过一圈即可。

直接做是 O ( n 2 log ⁡ ϵ − 1 ) O(n^2\log \epsilon^{-1}) O(n2logϵ1) 的,所以我们双指针预处理一下每条直线对应的下一条直线,然后倍增即可。

总复杂度 O ( n log ⁡ n log ⁡ ϵ − 1 ) O(n\log n\log \epsilon^{-1}) O(nlognlogϵ1)

代码

#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define lll __int128
#define uns unsigned
#define fi first
#define se second
#define IF (it->fi)
#define IS (it->se)
#define END putchar('\n')
#define lowbit(x) ((x)&-(x))
#define inline jzmyyds
using namespace std;
const int MAXN=1e5+5;
const ll INF=1e17;
ll read(){
	ll x=0;bool f=1;char s=getchar();
	while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
	while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
	return f?x:-x;
}
int ptf[50],lpt;
void print(ll x,char c='\n'){
	if(x<0)putchar('-'),x=-x;
	ptf[lpt=1]=x%10;
	while(x>9)x/=10,ptf[++lpt]=x%10;
	while(lpt>0)putchar(ptf[lpt--]^48);
	if(c>0)putchar(c);
}
using pdd=pair<double,double>;
const double PI=acos(-1),eps=1e-7;
int n,m,sr[MAXN],k;
pdd tran(const pdd&a){
	pdd b;
	b.se=sqrt(a.fi*a.fi+a.se*a.se),b.fi=acos(a.fi/b.se);
	if(a.se<0)b.fi=PI*2-b.fi;
	return b;
}
double dis(const pdd&a,const pdd&b){
	pdd c(a.fi-b.fi,a.se-b.se);
	return sqrt(c.fi*c.fi+c.se*c.se);
}
pdd pa[MAXN],a[MAXN];
double b[MAXN],ch;
double F(double w){
	if(w<0)w+=PI*2;
	if(w>PI*2)w-=PI*2;
	return min(w,PI*2-w);
}
int jp[MAXN][25];
double jb[MAXN][25];
bool inl(double y,double r,int x){
	double ck=F(a[x].fi-y);
	return ck*2<PI&&a[x].se*cos(ck)>=r-eps;
}
bool check(const double&r){
	for(int i=1;i<=n;i++){
		b[i]=a[i].fi+acos(r/a[i].se);
		while(b[i]<0)b[i]+=PI*2;
		while(b[i]>=PI*2)b[i]-=PI*2;
		sr[i]=i;
	}
	sort(sr+1,sr+1+n,[](int x,int y){return b[x]<b[y];});
	for(int i=1,j=1;i<=n;i++){
		int x=sr[i];
		if(i==j)j=(j==n?1:j+1);
		while(j!=i&&inl(b[x],r,sr[j]))j=(j==n?1:j+1);
		jp[i][0]=j,jb[i][0]=b[sr[j]]-b[x];
		if(jb[i][0]<eps)jb[i][0]+=PI*2;
	}
	for(int j=1;j<=18;j++)for(int i=1;i<=n;i++)
		jp[i][j]=jp[jp[i][j-1]][j-1],jb[i][j]=jb[i][j-1]+jb[jp[i][j-1]][j-1];
	for(int i=1;i<=n;i++){
		int x=i;double s=0;
		for(int j=18;j>=0;j--)if((m>>j)&1)s+=jb[x][j],x=jp[x][j];
		if(s>PI*2-eps)return 1;
	}
	return 0;
}
const bool PF=0;
int main()
{
	freopen("polygon.in","r",stdin);
	freopen("polygon.out","w",stdout);
	n=read(),m=read(),k=1,ch=INF;
	for(int i=1;i<=n;i++){
		int x=read(),y=read();
		if(x==0&&y==0)return printf("%.9f\n",0.0),0;
		a[i]=tran(pa[i]=pdd(x,y)),ch=min(ch,a[i].se);
	}
	if(m>=n||PF)return printf("%.9f\n",ch),0;
	double l=0,r=ch,mid;
	for(int NND=30;NND--;){
		mid=(l+r)/2;
		if(check(mid))l=mid;
		else r=mid;
	}
	printf("%.9f\n",mid);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算任意多边形的几何中心和重心需要用到多边形的顶点坐标。以下是使用MATLAB计算多边形几何中心和重心的方法: 假设多边形顶点坐标为 $P_1(x_1,y_1), P_2(x_2,y_2),...,P_n(x_n,y_n)$。 1. 计算几何中心 几何中心是所有顶点坐标的平均值,即: $$x_c=\frac{1}{n}\sum_{i=1}^{n} x_i$$ $$y_c=\frac{1}{n}\sum_{i=1}^{n} y_i$$ MATLAB代码如下: ```matlab % 输入顶点坐标 x = [x1, x2, ..., xn]; y = [y1, y2, ..., yn]; % 计算几何中心 xc = mean(x); yc = mean(y); ``` 2. 计算重心 重心是所有三角形重心的加权平均值,其中每个三角形的重心是三个顶点坐标的平均值。具体而言,对于第 $i$ 个三角形,其重心坐标为: $$x_i=\frac{1}{3}(x_{i1}+x_{i2}+x_{i3})$$ $$y_i=\frac{1}{3}(y_{i1}+y_{i2}+y_{i3})$$ 其中 $(x_{i1},y_{i1})$、$(x_{i2},y_{i2})$ 和 $(x_{i3},y_{i3})$ 是第 $i$ 个三角形的三个顶点坐标。 重心的坐标为所有三角形重心坐标的加权平均值,其中每个三角形的面积为其三个顶点构成的三角形面积的和,即: $$x_g=\frac{\sum_{i=1}^{n} S_i x_i}{\sum_{i=1}^{n} S_i}$$ $$y_g=\frac{\sum_{i=1}^{n} S_i y_i}{\sum_{i=1}^{n} S_i}$$ 其中 $S_i$ 是第 $i$ 个三角形的面积。 MATLAB代码如下: ```matlab % 输入顶点坐标 x = [x1, x2, ..., xn]; y = [y1, y2, ..., yn]; % 计算三角形面积和重心 S = 0; xg = 0; yg = 0; for i = 1:n-2 for j = i+1:n-1 for k = j+1:n % 计算第 i,j,k 个顶点组成的三角形面积 Si = abs((x(j)-x(i))*(y(k)-y(i))-(x(k)-x(i))*(y(j)-y(i)))/2; % 计算三角形重心坐标 xi = (x(i) + x(j) + x(k))/3; yi = (y(i) + y(j) + y(k))/3; % 更新重心坐标和三角形面积 xg = xg + Si*xi; yg = yg + Si*yi; S = S + Si; end end end % 计算重心坐标 xg = xg/S; yg = yg/S; ``` 注意,如果多边形是凸多边形,则几何中心和重心重合。如果多边形是凹多边形,则重心会偏离几何中心。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值