sgu120

来源:互联网 发布:苏州十大网络教育机构 编辑:程序博客网 时间:2024/04/30 13:11

SGU120 Archipelago
题目大意:

Ber群岛由N个岛屿组成。将岛屿视作点,则组成它的岛屿围成了一个正N边形。

将岛屿按顺时针标号,岛屿N1的坐标是(x1,y1),岛屿N2的坐标是(x2,y2)

你的任务是 得到 N1,N2的坐标 求出所有N个点的坐标

输入:

在第一行,输入 N ,N1 和 N2 (3 ≤ N ≤ 150, 1 ≤ N1,N2 ≤ N, N1 ≠ N2) 由空格隔开。

接下来两行输入 N1 和 N2 的坐标(坐标的绝对值不会大于 2000000)

输出:

输出N行,表示N个点的坐标,按照点的标号顺序输出。结果保留6位小数。

样例输入:

4 1 3

1.0000 0.0000

1.0000 2.0000

样例输出:

1.000000 0.000000

0.000000 1.000000

1.000000 2.000000

2.000000 1.000000


又是计算几何...
题目就是由两个点还原一个正多边形
为了方便,假定a<b

下面介绍向量旋转方法:
思想很简单:找到正多边形的中心(内心)(外心和内心是同一个...)
引用一些性质:
性质一:正多边形任意两点的连线的中垂线经过该正多边形的中心。
证明:根据中垂线性质:中垂线上的点到两点的距离相等。
      那么对于任意一个点i,i与其他点连线的中垂线交点到所有点的距离都相同。
      与正多边形所有点距离相同的点就是中心。

性质二:对于向量(x,y)在逆时针旋转a度之后得到向量为(x*cosa-y*sina,x*sina+y*cosa)
证明的话可以自己在草稿纸上画一画,很容易证明。

有了以上性质,我们可以给出大致思路
1.根据两个点的连线找出中垂线,并且大致判断出中心的方向(即从两点的中点指向中心的向量方向)。
  设中点为(xmid,ymid)
  从中点向b点指一个向量。
  若从a到b所经过的点>从b到a经过的点,则证明中心在a到b的方向上,将上面的向量逆时针旋转90°,否则将上面的向量顺时针旋转90°

2.根据两个点的序号关系得到两点与中心构成的中心角角度。
  对于两个点a、b,中心角度为:a、b两点连线与中心的另一端的边数*(360°/n)。

3.根据中心角角度和1中的向量方向计算出中心的坐标。
  设中心坐标为(xcenter,ycenter)
  xcenter=xmid+lx*t;
  ycenter=ymid+ly*t;
  tan(cita/2)=DIS(mid,a)/DIS(center,mid)
  将式子展开并合并,可以得到t与xcenter、ycenter。

4.从中心坐标引一条向量指向一个点。
5.通过旋转角度得到其他点的坐标。

听说有大神用相似做的,精度很高,但是很难想。

注意事项:1.计算机一般使用弧度制。
          2.WA在TEST5的OIer,请仔细检查向量的旋转(也有可能是cita/2的问题)。
下面附上我的代码:

#include <stdio.h>#include <stdlib.h>#include <math.h>#include <string.h>#define PI acos(-1)struct p{  double x,y;}point[200],mid,center,l;double numangle,length,cita,t,sum;int n,a,b;double SQR(double a){  return a*a;}double SQRDIS(struct p a,struct p b){  return SQR(a.x-b.x)+SQR(a.y-b.y);}struct p turn(struct p a,double angle)//(x,y)->(x*cosa-y*sina,x*sina+y*cosa){  struct p re;  re.x=a.x*cos(angle)-a.y*sin(angle);  re.y=a.x*sin(angle)+a.y*cos(angle);  return re;}struct p add(struct p a,struct p b){  struct p re;  re.x=b.x-a.x;  re.y=b.y-a.y;  return re;}void makepoint(){  int i;  l=add(center,point[a]);  i=a;  do  {  point[i].x=center.x+l.x;  point[i].y=center.y+l.y;  l=turn(l,-numangle);  i++;  if (i>n)    i=1;  }while (i!=a);  return ;}void work(){  if (b-a-1>a+n-b-1)    {l=turn(l,PI/2);cita=(a+n-b)*(numangle);    }  else    {    l=turn(l,-PI/2);    cita=(b-a)*(numangle);    }  cita/=2;  length=SQRDIS(mid,point[a]);  length/=SQR(tan(cita));  sum=SQR(l.x)+SQR(l.y);  t=sqrt(length/sum);  center.x=mid.x+l.x*t;  center.y=mid.y+l.y*t;  makepoint();  return ;}void init(){  int i;  scanf("%d",&n);  scanf("%d%d",&a,&b);  scanf("%lf%lf",&point[a].x,&point[a].y);  scanf("%lf%lf",&point[b].x,&point[b].y);  if (a>b)    { i=a; a=b; b=i; }  numangle=(2*PI/n);  mid.x=(point[a].x+point[b].x)/2;  mid.y=(point[a].y+point[b].y)/2;  l=add(mid,point[b]);  work();  for (i=1;i<=n;i++)    printf("%lf %lf\n",point[i].x,point[i].y);  return ;}int main(){  init();  return 0;}

0 0
原创粉丝点击