计算几何第一题,从没有做过几何题,每次看到就跳,今天是一个开始。
这题的递推是小事,重点是几何部分。我用的是高中的解析几何的做法,先求中垂线斜率,已知中点,然后通过距离来求出要求的点的坐标(PS:这题放在高中是超级水题啊,为什么写成C++这么烦)
几何部分代码:
void cal(int i,int j)
{
double l=2.0,h,d;
d=sqrt((dp[i].x-dp[j].x)*(dp[i].x-dp[j].x)+(dp[i].y-dp[j].y)*(dp[i].y-dp[j].y));
h=sqrt(2.0*2.0-d*d/4);
if(fabs(dp[i].y-dp[j].y)<1e-6)
{
ans.x=(dp[i].x+dp[j].x)/2;
ans.y=dp[i].y+h;
return;
}
double slope=-(dp[i].x-dp[j].x)/(dp[i].y-dp[j].y);
double k=sqrt(1+slope*slope);
int flag=1;
if(slope<0) flag=-1;
pt tmp;
tmp.x=(dp[i].x+dp[j].x)/2,tmp.y=(dp[i].y+dp[j].y)/2;
double dx=h/k;
ans.x=tmp.x+dx*flag;
ans.y=tmp.y+dx*fabs(slope);
}
后来看了网上别人的博客,发现可以这么写:
double a=acos(d/4) + atan((i.y-j.y)/(i.x-j.x));
ans.x=i.x+2*cos(acos(d/4) + atan((i.y-j.y)/(i.x-j.x)));
ans.y=i.y+2*sin(acos(d/4) + atan((i.y-j.y)/(i.x-j.x)));
只能说,叼叼叼!
完整代码:
#include <bits/stdc++.h>
using namespace std;
int n;
struct pt{
double x,y;
}dp[25],ans;
bool cmp(pt a,pt b){
return a.x<b.x;
}
void cal(int i,int j)
{
double l=2.0,h,d;
d=sqrt((dp[i].x-dp[j].x)*(dp[i].x-dp[j].x)+(dp[i].y-dp[j].y)*(dp[i].y-dp[j].y));
h=sqrt(2.0*2.0-d*d/4);
if(fabs(dp[i].y-dp[j].y)<1e-6)
{
ans.x=(dp[i].x+dp[j].x)/2;
ans.y=dp[i].y+h;
return;
}
double slope=-(dp[i].x-dp[j].x)/(dp[i].y-dp[j].y);
double k=sqrt(1+slope*slope);
int flag=1;
if(slope<0) flag=-1;
pt tmp;
tmp.x=(dp[i].x+dp[j].x)/2,tmp.y=(dp[i].y+dp[j].y)/2;
double dx=h/k;
ans.x=tmp.x+dx*flag;
ans.y=tmp.y+dx*fabs(slope);
}
int main()
{
while(~scanf("%d",&n)&&n)
{
for(int i=1;i<=n;i++)
{
scanf("%lf",&dp[i].x);
dp[i].y=1.0;
}
sort(dp+1,dp+n+1,cmp);
for(int i=n;i>=2;i--)
{
for(int j=1;j<i;j++)
{
cal(j,j+1);
dp[j]=ans;
}
}
printf("%.4lf %.4lf\n",dp[1].x,dp[1].y);
}
return 0;
}
总结:
1、多用用反三角函数吧
2、别再手贱了~