B. Rolling The Polygon

本文探讨了一个特定的数学问题,即计算凸多边形沿直线滚动时内部指定点的轨迹长度。通过定义多边形的顶点坐标和内部点坐标,利用几何原理和算法,详细阐述了解决方案的步骤,包括半径和旋转角度的计算,最终得出精确的轨迹长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  Bahiyyah has a convex polygon with n vertices P0, P1, · · · , Pn−1 in the counterclockwiseorder. Two vertices with consecutive(连续的)  indexes are adjacent(邻近的), and besides, P0 and Pn−1 are adjacent. She also assigns(指出) a point Q inside the polygon which may appear on the border.

  Now, Bahiyyah decides to roll the polygon along a straight line and calculate the length of the trajectory(弹道) (or track) of point Q.

  To help clarify, we suppose Pn = P0, Pn+1 = P1 and assume the edge between P0 and P1 is lying on the line at first. At that point when the edge between Pi−1 and Pi lies on the line, Bahiyyah rolls the polygon forward rotating(旋转) the polygon along the vertex Pi until the next edge (which is between Pi and Pi+1) meets the line. She will stop the rolling when the edge between Pn and Pn+1 (which is same as the edge between P0 and P1) meets the line again.

 

Input

The input contains several test cases, and the first line is a positive integer T indicating the number of test cases which is up to 50.

For each test case, the first line contains an integer n (3 ≤ n ≤ 50) indicating the number of vertices of the given convex polygon. Following n lines describe vertices of the polygon in the counterclockwise order. The i-th line of them contains two integers xi−1 and yi−1, which are the coordinates of point Pi−1. The last line contains two integers xQ and yQ, which are the coordinates of point Q.

We guarantee that all coordinates are in the range of −103 to 103, and point Q is located inside the polygon or lies on its border.

Output

For each test case, output a line containing Case #x: y, where x is the test case number starting from 1, and y is the length of the trajectory of the point Q rounded to 3 places. We guarantee that 4-th place after the decimal point in the precise answer would not be 4 or 5.  

题目理解

  题目描述很短,大意是现在有一个n边的凸多边形,给你这个多边形所有顶点的坐标。然后再给你多边形内一个点的坐标,接着滚动这个多边形一周,需要我们计算出目标点移动轨迹的长度。为了更好理解,题目第三段详细说明了如何滚动:假设P0为初始点,那么在P0和P1之间有一条边1,在P1和P2之间有一条边2,连接P0和P2也有一条边3,每次都沿着一条边滚动,且第一次都是沿着边1滚。如何停止呢?就是当滚动的边再一次是边1时就停止。可以认为最后是Pn和Pn+1之间的边,即Pn=P0,Pn+1=P1。

解题思路

  观察多边形和目标点滚动的方式和轨迹,可以知道每次滚动所形成的轨迹是一段弧长,那么为了求出此弧长则需要知道此弧长所在圆的半径和旋转的角度。对于半径,首先确定圆心即使滚动角的顶点(滚动角就是Pi、Pi+1和Pi+2所形成的夹角,那么滚动角顶点则是P1),而目标点则是圆边上的一点,那么半径= 滚动角顶点(v[i+1])到目标点(tv)的距离 = sqrt(pow(tv.x-ver[i+1].x,2)+pow(tv.y-ver[i+1].y,2));对于旋转角度就是180°减去滚动角的角度,三点坐标有了,Pi和Pi+1之间边a,那么就用余弦定理(复习下:cosx = (a^2 + b^2 - c^2)/(2ab))。旋转角度= 180°-滚动角° = π-acos((a*a+b*b-c*c)/(2*a*b)) ,(注:Pi和Pi+1之间边a,Pi+1和Pi+2之间边b,Pi和Pi+2之间边c);最后求弧长 = 半径 * 旋转角度即可。

  弧长计算的循环如果从P0开始,Pn-1结束,就设Pn=P0,Pn+1=P1,因为根据题意的停止条件(当边再次滚到初始的边1时,滚完即止,最后是Pn-1要和Pn和Pn+1构成一个角,那就要设Pn=P0,Pn+1=P1)。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <cstdio>
#include <vector>
#include <string>
#include <cmath>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#define inf 0x3f3f3f3f
const int maxn=1e5+10;
using namespace std;
typedef long long ll;
int x[100],y[100],xx,yy;
double dis[100],u[100];
#define PI acos(-1.0)


double calu(int a,int b)//计算半径
{
    return sqrt((a-xx)*(a-xx)+(b-yy)*(b-yy));
}
double caluu(int a,int b,int c,int d)
{
    return sqrt((a-c)*(a-c)+(b-d)*(b-d));
}

int main()
{
    int T;
    cin>>T;
    for(int j=1;j<=T;j++)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>x[i]>>y[i];
        }
        cin>>xx>>yy;
        for(int i=1;i<=n;i++)
        {
            dis[i]=calu(x[i],y[i]);
        }
        double t1,t2,t3;
        for(int i=1;i<=n;i++)
        {
            if(i==1)
            {
                t1=caluu(x[1],y[1],x[n],y[n]);
                t2=caluu(x[1],y[1],x[2],y[2]);
                t3=caluu(x[n],y[n],x[2],y[2]);
            }
            else if(i==n)
            {
                t1=caluu(x[n],y[n],x[1],y[1]);
                t2=caluu(x[n],y[n],x[n-1],y[n-1]);
                t3=caluu(x[1],y[1],x[n-1],y[n-1]);
            }
            else
            {
                t1=caluu(x[i],y[i],x[i+1],y[i+1]);
                t2=caluu(x[i],y[i],x[i-1],y[i-1]);
                t3=caluu(x[i-1],y[i-1],x[i+1],y[i+1]);
            }
            u[i]=acos((t1*t1+t2*t2-t3*t3)/(2*t1*t2)); //计算夹角
        }
        double sum=0;
        for(int i=1;i<=n;i++)
        {
            sum+=dis[i]*(PI-u[i]);//弧长 = 半径 * 旋转角度(180度-夹角)
        }
        printf("Case #%d: %.3lf\n",j,sum);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值