Python蓝桥杯练习 车轮轴迹

问题描述

  栋栋每天骑自行车回家需要经过一条狭长的林荫道。道路由于年久失修,变得非常不平整。虽然栋栋每次都很颠簸,但他仍把骑车经过林荫道当成一种乐趣。
  由于颠簸,栋栋骑车回家的路径是一条上下起伏的曲线,栋栋想知道,他回家的这条曲线的长度究竟是多长呢?更准确的,栋栋想知道从林荫道的起点到林荫道的终点,他的车前轮的轴(圆心)经过的路径的长度。
  栋栋对路面进行了测量。他把道路简化成一条条长短不等的直线段,这些直线段首尾相连,且位于同一平面内。并在该平面内建立了一个直角坐标系,把所有线段的端点坐标都计算好。
  假设栋栋的自行车在行进的过程中前轮一直是贴着路面前进的。

  上图给出了一个简单的路面的例子,其中蓝色实线为路面,红色虚线为车轮轴经过的路径。在这个例子中,栋栋的前轮轴从A点出发,水平走到B点,然后绕着地面的F点到C点(绕出一个圆弧),再沿直线下坡到D点,最后水平走到E点,在这个图中地面的坐标依次为:(0, 0), (2, 0), (4, -1), (6, -1),前轮半径为1.50,前轮轴前进的距离依次为:
  AB=2.0000;弧长BC=0.6955;CD=1.8820;DE=1.6459。
  总长度为6.2233。

  下图给出了一个较为复杂的路面的例子,在这个例子中,车轮在第一个下坡还没下完时(D点)就开始上坡了,之后在坡的顶点要从E绕一个较大的圆弧到F点。这个图中前轮的半径为1,每一段的长度依次为:
  AB=3.0000;弧长BC=0.9828;CD=1.1913;DE=2.6848;弧长EF=2.6224; FG=2.4415;GH=2.2792。
  总长度为15.2021。

  现在给出了车轮的半径和路面的描述,请求出车轮轴轨迹的总长度。

输入格式

  输入的第一行包含一个整数n和一个实数r,用一个空格分隔,表示描述路面的坐标点数和车轮的半径。
  接下来n行,每个包含两个实数,其中第i行的两个实数x[i], y[i]表示描述路面的第i个点的坐标。
  路面定义为所有路面坐标点顺次连接起来的折线。给定的路面的一定满足以下性质:

  第一个坐标点一定是(0, 0);
  
第一个点和第二个点的纵坐标相同;
  倒数第一个点和倒数第二个点的纵坐标相同;
  
第一个点和第二个点的距离不少于车轮半径;
  倒数第一个点和倒数第二个点的的距离不少于车轮半径;
  
后一个坐标点的横坐标大于前一个坐标点的横坐标,即对于所有的i,x[i+1]>x[i]。

输出格式

  输出一个实数,四舍五入保留两个小数,表示车轮轴经过的总长度。
  你的结果必须和参考答案一模一样才能得分。数据保证答案精确值的小数点后第三位不是4或5。

样例输入

4 1.50
0.00 0.00
2.00 0.00
4.00 -1.00
6.00 -1.00

样例输出

6.22

样例说明

  这个样例对应第一个图。

样例输入

6 1.00
0.00 0.00
3.00 0.00
5.00 -3.00
6.00 2.00
7.00 -1.00
10.00 -1.00

扫描二维码关注公众号,回复: 11462107 查看本文章
样例输出

15.20

样例说明

  这个样例对应第二个图

思路

轮子与地面永远是保持垂直的,在每段地面上画一个平行四边形,轮子总是沿着平行四边形的上面的边行走的
计算路面上方轴心位置时,可以根据线段与水平线的夹角与轮子半径以及对应地面点的坐标求得
首先可以将这个轮子轴心前进分为几种情况

  1. 平路、上坡、下坡:从起点上方,一直前进到轮子接触到上升坡或者拐点上方结束,判断轮子轴心结束该端的位置可以在当前地面画一个平行四边形,再在下一个地面画一个平行四边形,轮子总是沿着平行四边形的上面的边行走的,所以求两个平行四边形上面线的交点便是向上转折点,也是轮子前沿刚好接触到上升坡的位置,求两直线交点在后面补充
    轮子接触到上升坡
  2. 向下的转折点: 当下个平面与水平线的角度比当前平面低时,会产生向下的转折点,轮子与地面的接触点不变,轴绕接触点旋转,由于轮子始终与地面垂直,所以从一个平面的垂直点旋转到另一平面的旋转点,旋转角度为180°-两平面下面的夹角,根据半径和角度,计算出弧长,如果夹角大于180°,那么轮子是可以不用旋转的
    产生向下的转折点

产生向下的转折点

夹角大于180°,那么轮子是可以不用旋转的
3. 求两直线交点:
(1) 根据直线两点得到截距式,y=a*x+b,再解方程组就好了,注意垂直的情况要特殊考虑

    int a1 = (line1.point1.y - line1.point2.y) / (line1.point1.x - line1.point2.x);
    int b1 = line1.point1.y - a1 * (line1.point1.x);

    int a2 = (line2.point1.y - line2.point2.y) / (line2.point1.x - line2.point2.x);
    int b2 = line2.point1.y - a2 * (line2.point1.x);

    CrossP.x = (b1 - b2) / (a2 - a1);
    CrossP.y = a1 * CrossP.x + b1;

(2) 设想直线方程表达式为 Ax + by + C = 0,注意一般式表达直线时,当D = 0的时候要进行特殊的处理和判断,这里的一般式是由两点式推来的ABC

def GeneralEquation(first_x,first_y,second_x,second_y):
    # 一般式 Ax+By+C=0
    # from http://www.cnblogs.com/DHUtoBUAA/
    A=second_y-first_y
    B=first_x-second_x
    C=second_x*first_y-first_x*second_y
    return A,B,C

def GetIntersectPointofLines(x1,y1,x2,y2,x3,y3,x4,y4):
    # from http://www.cnblogs.com/DHUtoBUAA/
    A1,B1,C1=GeneralEquation(x1,y1,x2,y2)
    A2, B2, C2 = GeneralEquation(x3,y3,x4,y4)
    m=A1*B2-A2*B1
    if m==0:
        print("平行,无交点")
    else:
        x=(C2*B1-C1*B2)/m
        y=(C1*A2-C2*A1)/m
    return x,y

(3) 也有用最小二乘法,不断缩小精度得到的,感觉不是很好用

Python源代码

害..

猜你喜欢

转载自www.cnblogs.com/heyjjjjj/p/J.html