题解 P3744 【李彬的几何】
Richard1211 · · 题解
这题这其实是一个几何问题
前置知识
你需要知道什么是凸多边形和凹多边形
你还需要知道求三角形面积的海伦公式:已知一个一般三角形的三边
海伦公式的证明:
设三角形的三边
从而有
因此三角形的面积
其中
最后你要知道勾股定理(这个应该没人不知道吧)
给你一个直角三角形,以及直角三角形的两条直角边
解题思路
我们不难想到,让一个凸多边形变成不是凸多边形,其实就是让一个凸多边形变成凹四边形,具体怎么转换呢?我们不妨看一张图
可以看出,让凸四边形变成凹四边形的方法就是把其中一个顶点的旁边两个点固定,然后把这个顶点移动一定的距离,而题目让我们求的距离就是这个顶点移动的距离的最小值
想要让
不妨设我们要移动的顶点是
此时图中的
接下来我们看看怎么算
首先题目已经告诉了我们每个点的坐标,于是我们就可以用两点之间的距离公式
(其中
来计算边
先来证明一下两点之间的距离公式,首先我们选择平面上的任意两个点
然后我们可以做几条辅助线,如下图
我们做出一个直角三角形,然后根据给定的坐标可以算出两条直角边的长度是
然后我们要求的是红色边的长度,我们就可以使用勾股定理
进一步化简即可得到
然后我们使用三角形的面积公式
进一步变形我们得到
我们令
而且题目说我们不仅仅只能移动一个点,可以移动多个,只要范围都在
我们可以看到,在最优的情况下,
接下来的步骤就简单了,照着公式写代码即可,但还要注意一些细节,比如这题在算两点之间的距离 (这个应该没人会错吧),这样写出来的代码就没问题了。
还有一些注释可以见代码。
Code
#include <bits/stdc++.h>
using namespace std;
template<class T>T Min(register T a,register T b){
return a<b?a:b;
}
template<class T>T Max(register T a,register T b){
return a>b?a:b;
}
template<class T>T Abs(register T a){
return a>0?a:-a;
}
template<class T>void Swap(register T &a,register T &b){
T t=a;
a=b;
b=t;
}
//更快的min,max,abs,swap
const long long N=100100;
long long X[N],Y[N];
double dis(long long x,long long y){
return sqrtl((X[x]-X[y])*(X[x]-X[y])+(Y[x]-Y[y])*(Y[x]-Y[y]));//算平面上两个点的距离
}
double Dis(long long x,long long y,long long z){//算把Y点移动d距离变成凹多边形时d的最小值
double dx=dis(x,y);
double dy=dis(y,z);
double dz=dis(z,x);
double p=(dx+dy+dz)/2.0;//半周长p
double s=sqrtl(p*(p-dx)*(p-dy)*(p-dz));
return s*1.0/dz/**2.0*/;//由于题目说每个点都能移动d,所以可以进一步缩短一半,原来推出来的公式中的*2就和/2抵掉了,所以就不用*2了
}
int main(){
long long n;
scanf("%lld",&n);
for(long long i=1;i<=n;i++){
scanf("%lld%lld",&X[i],&Y[i]);
}
double ans=Min(Dis(n,1,2),Dis(n-1,n,1));
for(long long i=2;i<=n-1;i++){
ans=Min(ans,Dis(i-1,i,i+1));
}
printf("%.10lf\n",ans);
return 0;
}
于是这题就做完了。
另外,安利一下蒟蒻的博客
求管理员大大通过qwq