Nyoj 298 点的变换[利用矩阵求解坐标点的转换,平移,绕原点旋转,沿x,y轴翻转]

2024-06-07 03:38

本文主要是介绍Nyoj 298 点的变换[利用矩阵求解坐标点的转换,平移,绕原点旋转,沿x,y轴翻转],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接:acm.nyist.net/JudgeOnline/problem.php?pid=298

题目的意思就是给你一n个点(n<=10000),求m次操作后(m<=1000000),各点变为什么了?操作有:平移,绕原点旋转,沿x,y轴翻转。

思路,利用矩阵相乘来解决。。这个很有意思。。

先来补充一下矩阵相乘的知识。。。。

First, 我们必须需要知道的是,矩阵相乘满足结合律,但是, 不满足交换律。。

接下来补充Matrix67大神总结的:

这里的操作是对所有点同时进行的。其中翻转是以坐标轴为对称轴进行翻转(两种情况),旋转则以原点为中心。如果对每个点分别进行模拟,那么m个操作总共耗时O(mn)。利用矩阵乘法可以在O(m)的时间里把所有操作合并为一个矩阵,然后每个点与该矩阵相乘即可直接得出最终该点的位置,总共耗时O(m+n)。假设初始时某个点的坐标为x和y,下面5个矩阵可以分别对其进行平移、旋转、翻转和旋转操作。预先把所有m个操作所对应的矩阵全部乘起来,再乘以(x,y,1),即可一步得出最终点的位置。
    

刚开始,没有理解他的精髓。。

以为每次每个操作都需要把每个点都变换,这样复杂度就是n*3*3*m了。。。O(mn)的复杂度。。。时间复杂度简直报表啊。。表示,理解错误了。。。。

我们根据结合律可以知道,m次操作是可以先结合的。。。最后求点的坐标。。3*3*3*m + n的复杂度。。时间复杂度O(m + n)的,可以接受的。。。

Code:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>using namespace std;const int N = 4;
const int M = 1e4 + 5;
const double PI = acos(-1);struct POINT
{double x, y;
} p[M];struct Matrix
{int n, m;double a[N][N];Matrix(){memset(a, 0, sizeof(a));}Matrix (int x, int  y){n = x;m = y;memset(a, 0, sizeof(a));}
} ans;Matrix operator * (Matrix a, Matrix b)
{Matrix tans;tans.n = a.n;tans.m = b.m;for(int i = 1 ; i <= a.n; i ++){for(int j = 1; j <= b.m; j ++){for(int k = 1; k <= b.n; k ++)tans.a[i][j] += a.a[i][k] * b.a[k][j];}}return tans;
}Matrix Rotation(double r)// rotation, turn left ? turn right?
{Matrix op;op.n = 3;op.m = 3;op.a[1][1] = cos(r);op.a[1][2] = sin(r);op.a[2][1] = -sin(r);op.a[2][2] = cos(r);op.a[3][3] = 1;//trun by the base of (0, 0);return ans * op;
}Matrix go(double px, double py)
{Matrix op;op.n = 3;op.m = 3;op.a[1][1] = 1.0;op.a[2][2] = 1.0;op.a[3][3] = 1.0;op.a[3][1] = px;op.a[3][2] = py;return ans * op;
}Matrix bigger(double p)
{Matrix op;op.n = 3;op.m = 3;op.a[1][1] = p;op.a[2][2] = p;op.a[3][3] = 1;return ans * op;
}Matrix fx()
{Matrix op;op.n = 3;op.m = 3;op.a[1][1] = 1.0;op.a[2][2] = -1.0;op.a[3][3] = 1.0;return ans * op;
}Matrix fy()
{Matrix op;op.n = 3;op.m = 3;op.a[1][1] = -1.0;op.a[2][2] = 1.0;op.a[3][3] = 1.0;return ans * op;
}int main()
{
//    freopen("1.txt", "r", stdin);int n, m;scanf("%d %d", &n, &m);for(int i = 1; i <= n; i ++){scanf("%lf %lf", &p[i].x, &p[i].y);}getchar();ans.n= 3;ans.m = 3;for(int i = 1; i <= 3; i ++) ans.a[i][i] = 1.0;char order;for(int i = 1; i <= m; i ++){scanf("%c", &order);if(order == 'X') ans = fx();if(order == 'Y') ans = fy();if(order == 'M'){double  tmpx, tmpy;cin >> tmpx >> tmpy;ans = go(tmpx, tmpy);}if(order == 'S'){double tmps;cin >> tmps;ans = bigger(tmps);}if(order == 'R'){double tmpr;cin >> tmpr;ans = Rotation(tmpr / 180.0 * PI);}getchar();}for(int i = 1; i <= n; i ++){printf("%.1lf %.1lf\n", p[i].x * ans.a[1][1] + p[i].y * ans.a[2][1] + ans.a[3][1], p[i].x * ans.a[1][2] + p[i].y * ans.a[2][2] + ans.a[3][2]);}return 0;
}

代码虽然有点长,但是,直观性还是很好的。。


这篇关于Nyoj 298 点的变换[利用矩阵求解坐标点的转换,平移,绕原点旋转,沿x,y轴翻转]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1038065

相关文章

Java数字转换工具类NumberUtil的使用

《Java数字转换工具类NumberUtil的使用》NumberUtil是一个功能强大的Java工具类,用于处理数字的各种操作,包括数值运算、格式化、随机数生成和数值判断,下面就来介绍一下Number... 目录一、NumberUtil类概述二、主要功能介绍1. 数值运算2. 格式化3. 数值判断4. 随机

C语言中自动与强制转换全解析

《C语言中自动与强制转换全解析》在编写C程序时,类型转换是确保数据正确性和一致性的关键环节,无论是隐式转换还是显式转换,都各有特点和应用场景,本文将详细探讨C语言中的类型转换机制,帮助您更好地理解并在... 目录类型转换的重要性自动类型转换(隐式转换)强制类型转换(显式转换)常见错误与注意事项总结与建议类型

Python实现视频转换为音频的方法详解

《Python实现视频转换为音频的方法详解》这篇文章主要为大家详细Python如何将视频转换为音频并将音频文件保存到特定文件夹下,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5. 注意事项

使用Python实现图片和base64转换工具

《使用Python实现图片和base64转换工具》这篇文章主要为大家详细介绍了如何使用Python中的base64模块编写一个工具,可以实现图片和Base64编码之间的转换,感兴趣的小伙伴可以了解下... 简介使用python的base64模块来实现图片和Base64编码之间的转换。可以将图片转换为Bas

css实现图片旋转功能

《css实现图片旋转功能》:本文主要介绍了四种CSS变换效果:图片旋转90度、水平翻转、垂直翻转,并附带了相应的代码示例,详细内容请阅读本文,希望能对你有所帮助... 一 css实现图片旋转90度.icon{ -moz-transform:rotate(-90deg); -webkit-transfo

Linux使用dd命令来复制和转换数据的操作方法

《Linux使用dd命令来复制和转换数据的操作方法》Linux中的dd命令是一个功能强大的数据复制和转换实用程序,它以较低级别运行,通常用于创建可启动的USB驱动器、克隆磁盘和生成随机数据等任务,本文... 目录简介功能和能力语法常用选项示例用法基础用法创建可启动www.chinasem.cn的 USB 驱动

numpy求解线性代数相关问题

《numpy求解线性代数相关问题》本文主要介绍了numpy求解线性代数相关问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 在numpy中有numpy.array类型和numpy.mat类型,前者是数组类型,后者是矩阵类型。数组

Python 标准库time时间的访问和转换问题小结

《Python标准库time时间的访问和转换问题小结》time模块为Python提供了处理时间和日期的多种功能,适用于多种与时间相关的场景,包括获取当前时间、格式化时间、暂停程序执行、计算程序运行时... 目录模块介绍使用场景主要类主要函数 - time()- sleep()- localtime()- g

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

Java将时间戳转换为Date对象的方法小结

《Java将时间戳转换为Date对象的方法小结》在Java编程中,处理日期和时间是一个常见需求,特别是在处理网络通信或者数据库操作时,本文主要为大家整理了Java中将时间戳转换为Date对象的方法... 目录1. 理解时间戳2. Date 类的构造函数3. 转换示例4. 处理可能的异常5. 考虑时区问题6.