首页 > 其他分享 >【CSP】坐标变换2(问题拆解,快速输入,知识补充)

【CSP】坐标变换2(问题拆解,快速输入,知识补充)

时间:2024-08-30 15:51:22浏览次数:6  
标签:读取 double 旋转 拆解 坐标 缓冲区 theta CSP 输入

1. 题目背景与任务分析

题目背景
本题要求对二维平面上的点进行指定角度的旋转,并输出旋转后的坐标,要求精确到小数点后六位。这类题目广泛用于考察选手对数学计算、坐标变换以及编程语言中浮点数处理的能力。

任务明确

  • 输入:多个坐标点及旋转角度。
  • 输出:旋转后的新坐标,精确到小数点后六位。

分析与难点

  • 几何计算:利用旋转矩阵进行坐标变换。
  • 精度控制:确保输出结果满足精度要求,避免浮点数误差。
  • 高效输入输出:优化大量数据的输入输出效率。

2. 问题拆解与功能模块设计

总问题:如何准确、高效地实现坐标旋转并满足精度要求?

子问题划分

  1. 坐标旋转计算公式推导

    • 任务:如何通过旋转矩阵公式计算旋转后的新坐标?
    • 方案:使用三角函数计算旋转矩阵。
  2. 浮点数精度输出

    • 任务:如何确保输出精确到小数点后六位?
    • 方案:使用printf的格式化输出控制输出精度。
  3. 高效输入输出优化

    • 任务:如何处理大量数据的输入输出?
    • 方案:通过自定义快速输入函数,并设定合理的缓冲区大小。

3. 子问题的详细解决方案

子问题1:坐标旋转公式的推导与实现

  • 公式推导:旋转矩阵的推导基于三角函数的和差公式。假设旋转前的点坐标为 (x,y)(x, y)(x,y),旋转角度为 θ\thetaθ,则旋转后的坐标可以通过以下公式计算:

    double x_new = x * cos(theta) - y * sin(theta);
    double y_new = x * sin(theta) + y * cos(theta);
    

子问题2:浮点数精度的输出

  • 精度控制:C++中可以通过printf("%.6f", value)来保证输出精确到小数点后六位。
  • 格式说明%.6f表示输出一个浮点数,精确到小数点后六位。
  • 代码实现
    printf("%.6f %.6f\n", x_new, y_new);
    

子问题3:高效输入输出优化

  • 手动设定缓冲区:通过设定合理大小的缓冲区,并使用fread批量读取数据,提高了I/O效率。

  • 代码实现

    char buf[1 << 24], *p1 = buf, *p2 = buf;
    #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 24, stdin), p1 == p2) ? EOF : *p1++)
    
    inline int read() {
        int x = 0;
        char ch = getchar();
        while (ch < '0' || ch > '9') ch = getchar();
        while (ch >= '0' && ch <= '9') {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x;
    }
    


4. 弧度制与角度制的转换

弧度与角度的关系
在C++编程中,sincos等函数使用弧度制。因此,若角度以度数给出,需要转换为弧度:

double theta_radian = theta_degree * M_PI / 180.0;

5. 常用数学函数与头文件

数学函数总结

函数名功能用法头文件
sin计算正弦值sin(弧度)<cmath>
cos计算余弦值cos(弧度)<cmath>
atan2计算两点之间的角度atan2(y, x)<cmath>
sqrt计算平方根sqrt(x)<cmath>
pow计算幂次pow(base, exp)<cmath>

6. doublefloat的比较与选择

主要区别

  • 精度double为64位,float为32位,因此double能提供更高的精度。
  • 内存占用double占用8字节,float占用4字节。
  • 使用场景double适用于需要高精度计算的场景,如科学计算、金融分析等。

选择建议:在竞赛题目中,为了减少因精度不足导致的错误,推荐使用double

7. 浮点数快速输入的实现与分析

在竞赛中,处理大规模输入输出是一个关键的优化点。为了实现快速的浮点数输入,我们可以手动设置缓冲区大小,并通过自定义的输入函数来提高效率。这一部分将详细解释这种方法的实现和原理,并对代码中的每个变量进行详细的说明。

浮点数快速输入的代码实现
#include <cstdio> // 包含标准I/O函数,如fread, printf

char buf[1 << 24], *p1 = buf, *p2 = buf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 24, stdin), p1 == p2) ? EOF : *p1++)

// 自定义快速输入函数
inline double read_double() {
    double x = 0, factor = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') factor = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    if (ch == '.') {
        double frac = 1;
        ch = getchar();
        while (ch >= '0' && ch <= '9') {
            frac /= 10;
            x += (ch - '0') * frac;
            ch = getchar();
        }
    }
    return x * factor;
}
代码详解与变量说明
  1. char buf[1 << 24], *p1 = buf, *p2 = buf;

    • buf: 定义了一个字符数组,用作输入缓冲区。1 << 24表示将整数1左移24位,这相当于2^24,即16777216字节(大约16MB)。这是一个非常大的缓冲区,可以一次性存储大量的输入数据。
    • p1: 指向缓冲区的当前读取位置。
    • p2: 指向缓冲区的末尾,或者说是数据的读取结束位置。
    • 作用: 通过定义这样一个大的缓冲区,可以减少fread函数的调用次数,从而提高数据读取的效率。
  2. #define getchar()

    • 定义: 自定义一个getchar函数,用来从缓冲区读取下一个字符。
    • 实现原理:
      • p1p2相等时,表示缓冲区的数据已经读取完毕,此时需要调用fread函数从标准输入(通常是键盘输入)再读取一批数据到缓冲区。
      • 如果fread返回的数据量为0,表示输入结束,getchar函数返回EOF(End of File,表示文件结束)。
      • 否则,p1自增,从缓冲区读取下一个字符并返回。
    • 作用: 高效地读取输入,避免频繁地进行I/O操作。
  3. fread(buf, 1, 1 << 24, stdin)

    • 功能: 从标准输入(stdin)中读取数据到缓冲区buf中。
    • 参数:
      • buf: 数据存储的目标缓冲区。
      • 1: 每次读取的单位大小为1字节。
      • 1 << 24: 总共读取的字节数,即16777216字节。
      • stdin: 指定读取的来源为标准输入。
    • 原理: 一次性读取大量数据到缓冲区,从而减少I/O操作的开销。
    • 应用场景: 适用于处理大规模数据输入的场景,如竞赛题目或需要高效读取大文件的情况。
  4. inline double read_double()

    • 功能: 快速读取一个浮点数。
    • 过程:
      • 首先通过getchar跳过非数字字符(如空格、换行符)。
      • 检测到负号时,将factor设为-1以处理负数输入。
      • 读取整数部分,通过累加的方式将字符转换为对应的数值。
      • 如果遇到小数点,则进入小数部分的处理,逐位将小数部分转化并累加到x中。
    • 变量作用:
      • x: 用来存储读取到的浮点数的值。
      • factor: 用来处理负数情况。
      • frac: 用于计算小数部分的分数值。
    • 优势: 与标准的输入函数相比,这种方法减少了I/O操作次数,并且直接处理了小数部分的输入,效率更高。
理解1 << 24 表达式的意义
  • 1 << 24 是一个位操作符,它将1的二进制位向左移动24位,结果是16777216。这个值表示缓冲区的大小,即我们一次性可以读取的最大字节数。
fread()函数的工作原理
  • fread 是C标准库中的一个函数,用来从文件或标准输入中读取数据。其工作方式是直接从I/O流中读取指定数量的字节并存储到缓冲区中,从而减少频繁的I/O操作。
EOF的意义
  • EOF (End of File) 是一个常量,用来标识输入流的结束。它通常在读取到输入的末尾或者在fread函数返回0字节时被返回。

8.手动设定缓冲区大小的方案 vs 使用系统规定大小的方案

1. 手动设定缓冲区大小的方案

  • 优点:

    • 控制更精确:可以根据具体情况设定缓冲区的大小,最大化内存使用效率。
    • 大数据处理效率高:对于非常大的数据量,手动设定较大的缓冲区可以减少I/O操作次数,提高输入输出效率。
  • 缺点:

    • 内存占用大:手动设置的缓冲区大小如果过大,可能会导致内存占用过高,不适合在内存资源有限的环境中使用。
  • 适用场景:

    • 竞赛场景或者大数据处理场景,输入输出数据量巨大,且需要极高的I/O效率。

2. 使用系统规定大小的方案

  • 优点:

    • 内存使用灵活:缓冲区大小由系统管理,通常不会占用过多内存。
    • 适合通用场景:对于一般的程序,这种方式已经足够满足需求,无需额外调优。
  • 缺点:

    • 效率稍低:由于系统缓冲区的大小不一定最优,因此在处理大规模数据时,效率可能不如手动设置缓冲区。
  • 适用场景:

    • 通用的编程场景,不需要极致优化输入输出的场合。

9. 最终代码与详细注释

#include <iostream>
#include <cmath>    // 包含数学函数头文件,如sin, cos, atan2, sqrt
#include <cstdio>   // 用于printf, scanf等C风格的I/O操作
using namespace std;

int main() {
    double x, y, theta;
    
    // 输入坐标(x, y)和旋转角度theta
    scanf("%lf %lf %lf", &x, &y, &theta);

    // 将角度转化为弧度制
    theta = theta * M_PI / 180.0;  // M_PI为π的值,直接转换为弧度
    
    // 计算cos(theta)和sin(theta)
    double cos_theta = cos(theta);
    double sin_theta = sin(theta);

    // 使用旋转矩阵计算新的坐标(x', y')
    double x_new = x * cos_theta - y * sin_theta;
    double y_new = x * sin_theta + y * cos_theta;

    // 按照题目要求,精确到小数点后6位输出结果
    printf("%.6f %.6f\n", x_new, y_new);

    return 0;
}

代码分析

  1. 输入部分:使用scanf读取输入的坐标和角度,并将其存储为double类型以保证精度。

  2. 角度转弧度:计算旋转矩阵时,三角函数的参数为弧度,因此需要将角度转换为弧度。

  3. 旋转矩阵的计算:根据旋转矩阵公式,利用计算出来的cos_thetasin_theta计算新的坐标。

  4. 精度控制的输出:使用printf("%.6f")确保输出的结果精确到小数点后六位。


10. 总结与启发

总结

在这道题目中,我们通过旋转矩阵公式解决了二维平面上的坐标旋转问题,并且通过对浮点数的精度控制,满足了输出精度要求。我们还讨论了如何通过设定缓冲区和自定义输入函数优化大规模数据的输入输出效率。

启发

  1. 几何问题的推广:旋转矩阵的思路不仅适用于二维旋转,还可以推广到三维或更高维度的旋转问题,甚至可以应用于计算机图形学中的各种变换操作。

  2. 精度控制的重要性:在涉及到浮点数运算的题目中,精度控制是至关重要的。了解并合理使用C++中的格式化输出可以有效避免因为精度丢失导致的错误。

  3. 高效输入输出的技巧:设定缓冲区大小和自定义快速输入函数可以大大提高程序的执行效率,特别是在数据量大的竞赛题目中。


以上就是完整的文章内容,涵盖了从问题分析、子问题解决到最终代码实现的全过程,并详细解释了各个步骤中的关键点和设计选择。这种思路和方法不仅适用于本题目,还可以推广应用到其他涉及数学计算和数据处理的题目中。

标签:读取,double,旋转,拆解,坐标,缓冲区,theta,CSP,输入
From: https://blog.csdn.net/weixin_72391681/article/details/141719951

相关文章

  • CSP-J 2021 初赛试题解析(第三部分:完善程序(2))
    完善程序二完整程序代码#include<iostream>usingnamespacestd;structpoint{intx,y,id;};boolequals(pointa,pointb){returna.x==b.x&&a.y==b.y;}boolcmp(pointa,pointb){returna.x!=b.x?a.x<b.x:a.y<b.y;}......
  • appsettins.json 复制到输出文件夹 CopyToOutpuDirectory 配置文件 csproj
    复制配置文件到输出文件夹<ItemGroup><NoneUpdate="appsettings.json"><CopyToOutputDirectory>Always</CopyToOutputDirectory></None><NoneUpdate="nlog.config"CopyToOutputDirectory="Always&qu......
  • P7075 [CSP-S2020] 儒略日 题解
    P7075[CSP-S2020]儒略日题面:题目描述为了简便计算,天文学家们使用儒略日(Julianday)来表达时间。所谓儒略日,其定义为从公元前4713年1月1日正午12点到此后某一时刻间所经过的天数,不满一天者用小数表达。若利用这一天文学历法,则每一个时刻都将被均匀的映射到数轴......
  • 【问题总结】Garmin路线无法同步和地图坐标偏移的解决过程
          在GarminConnectAPP或网页上面自己创建的路线(不是通过已经跑过或骑行的历史记录另存的线路),同步到设备时提示不支持(无兼容设备),历史记录另存的路线如果进行了标注等修改,也会出现同样的无法同步问题。联系客服了解并从网上查阅资料,说是在GarminConnect网页版上使用......
  • CSP-S初赛知识点汇总
    CSP-S初赛知识点汇总进制转换二进制整数部分略。小数部分将小数点后部分整体*2,取其整数部分的结果即为对应二进制数字。之后,取计算后的数字小数部分继续计算直到其全为0为止。举一个例子:将33.25转化为二进制数整数部分:33/2=16......116/2=8......08/2=4......0......
  • YOLOv9添加DCNv4可变性卷积与RepNCSPELAN4结构融合(windows系统成功编译),全网最详细教
    前言引入了可变形卷积v4(DCNv4),这是一种为广泛视觉应用设计的高效且有效的操作算子。DCNv4通过两项关键增强解决了其前身DCNv3的局限性:1.移除空间聚合中的softmax归一化,以增强其动态特性和表达能力;2.优化内存访问以最小化冗余操作,从而加速计算。这些改进使得DCNv4相......
  • 历年CSP-J初赛真题解析 | 2016年CSP-J初赛阅读程序(23-26)
    学习C++从娃娃抓起!记录下CSP-J备考学习过程中的题目,记录每一个瞬间。附上汇总贴:历年CSP-J初赛真题解析|汇总_热爱编程的通信人的博客-CSDN博客#include<iostream>usingnamespacestd;intmain(){intmax,min,sum,count=0;inttmp;cin>>tmp;......
  • YOLOv9改进策略【卷积层】| 利用MobileNetv4中的UIB、ExtraDW优化RepNCSPELAN4
    一、本文介绍本文记录的是利用ExtraDW优化YOLOv9中的RepNCSPELAN4,详细说明了优化原因,注意事项等。ExtraDW是MobileNetv4模型中提出的新模块,允许以低成本增加网络深度和感受野,具有ConvNext和IB的组合优势。可以在提高模型精度的同时降低一定量的模型参数。文章目录一、......
  • 南沙区信奥赛CSP-J/S 陈老师解题:1350:【例4-11】最短网络(agrinet)
    ​ 【题目描述】农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了用最小的消费,他想铺设最短的光纤去连接所有的农场。你将得到一......
  • 2024 CCF举办关于CSP-J/S的通知
    ​CCF面向社会非专业人士推出CSP非专业级别软件能力认证。非专业级别能力认证CSP-J/S分两个级别,分别为CSP-J(入门级,Junior)和CSP-S(提高级,Senior),均涉及算法和编程。任何人都可以报名参加。一、认证形式:CSP-J/S分第一轮和第二轮两个认证阶段。报名参加第一轮认证成绩优异者进入第二......