NYOJ 298

利用矩阵来做变换,参考Max大神的思想的,虽然不是同一道题。

-----------

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

转自M67大神

------

以下是NYOJ的练习题

感觉这种做法是十分巧妙的。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
struct Matrax {
	double m[3][3];
};
double PI;
struct Point {
	double x,y;
}p[10100];

void init(Matrax &p){
	for(int i=0;i<3;i++)
	for(int j=0;j<3;j++)
	p.m[i][j]=0;
}

Matrax enM(double L,double P){
	Matrax c;
	init(c);
	c.m[0][0]=c.m[1][1]=c.m[2][2]=1;
	c.m[0][2]=L;c.m[1][2]=P;
	return c;
}

Matrax enX(){
	Matrax c;
	init(c);
	c.m[1][1]=-1;
	c.m[0][0]=c.m[2][2]=1;
	return c;
}

Matrax enY(){
	Matrax c;
	init(c);
	c.m[0][0]=-1;
	c.m[1][1]=c.m[2][2]=1;
	return c;
}

Matrax enS(double P){
	Matrax c;
	init(c);
	c.m[1][1]=P;
	c.m[0][0]=P;c.m[2][2]=1;
	return c;
}

Matrax enR(double R){
	Matrax c;
	init(c);
	c.m[0][0]=cos(R);c.m[0][1]=-1*sin(R);
	c.m[1][0]=sin(R);c.m[1][1]=cos(R);
	c.m[2][2]=1;
	return c;
}

Matrax multi(Matrax a,Matrax b){
	Matrax c;
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			c.m[i][j]=0;
			for(int k=0;k<3;k++)
			c.m[i][j]+=a.m[i][k]*b.m[k][j];
		}
	}
	return c;
}

int main(){
	PI=acos(-1.0);
	int N,M;
	double ts[3];
	char t; double x,y,L,P,R;
	while(scanf("%d %d",&N,&M)!=EOF){
		Matrax ans;
		init(ans);
		ans.m[0][0]=ans.m[1][1]=ans.m[2][2]=1;
		for(int i=0;i<N;i++)
		scanf("%lf%lf",&p[i].x,&p[i].y);
		for(int i=0;i<M;i++){
			cin>>t;
			Matrax tt;
			if(t==‘X‘){
				tt=enX();
				ans=multi(tt,ans);
			}
			else if(t==‘Y‘){
				tt=enY();
				ans=multi(tt,ans);
			}
			else if(t==‘M‘){
				scanf("%lf%lf",&L,&P);
				tt=enM(L,P);
				ans=multi(tt,ans);
			}
			else if(t==‘S‘){
				scanf("%lf",&P);
				tt=enS(P);
				ans=multi(tt,ans);
			}
			else if(t==‘R‘){
				scanf("%lf",&R);
				R=PI*R/180.0;
				tt=enR(R);
				ans=multi(tt,ans);
			}
		}
		for(int i=0;i<N;i++){
			ts[0]=p[i].x; ts[1]=p[i].y; ts[2]=1;
			double ansx=ts[0]*ans.m[0][0]+ts[1]*ans.m[0][1]+ts[2]*ans.m[0][2];
			if(fabs(ansx-0)<1e-8) ansx=0;
			double ansy=ts[0]*ans.m[1][0]+ts[1]*ans.m[1][1]+ts[2]*ans.m[1][2];
			if(fabs(ansy-0)<1e-8) ansy=0;
			printf("%.1lf %.1lf\n",ansx,ansy);
		}
	}
	return 0;
}

  

时间: 2024-08-11 07:42:00

NYOJ 298的相关文章

NYOJ 298 点的变换

题目链接:298 点的变换 这题放在矩阵快速幂里,我一开始想不透它是怎么和矩阵搭上边的,然后写了个暴力的果然超时,上网看了题解后,发现竟然能够构造一些精巧的矩阵来处理,不得不说实在太强大了! http://blog.csdn.net/lyhvoyage/article/details/39755595 然后我的代码是: 1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdl

NYOJ 298 点的变换(矩阵快速幂)

点的变换 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 平面上有不超过10000个点,坐标都是已知的,现在可能对所有的点做以下几种操作: 平移一定距离(M),相对X轴上下翻转(X),相对Y轴左右翻转(Y),坐标缩小或放大一定的倍数(S),所有点对坐标原点逆时针旋转一定角度(R). 操作的次数不超过1000000次,求最终所有点的坐标. 提示:如果程序中用到PI的值,可以用acos(-1.0)获得. 输入 只有一组测试数据 测试数据的第一行是两个整数N,M,分别表示

NYOJ 298 相变点(矩阵高速功率)

点的变换 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描写叙述 平面上有不超过10000个点.坐标都是已知的.如今可能对全部的点做下面几种操作: 平移一定距离(M),相对X轴上下翻转(X),相对Y轴左右翻转(Y),坐标缩小或放大一定的倍数(S),全部点对坐标原点逆时针旋转一定角度(R). 操作的次数不超过1000000次,求终于全部点的坐标. 提示:假设程序中用到PI的值,能够用acos(-1.0)获得. 输入 仅仅有一组測试数据 測试数据的第一行是两个整数N,M,分

NYOJ 298-点的变换(经典矩阵解决点平移、缩放、翻转和旋转)

题目地址:NYOJ 298 思路:该题如果用对每个点模拟的操作,时间复杂度为O(n+m),结果肯定超时.然而利用矩阵乘法可以在O(m)的时间内把所有的操作合并为一个矩阵,然后每个点与该矩阵相乘可以得出最终的位置. PS:十个利用矩阵乘法解决的经典题目 超级详细. #include <stdio.h> #include <math.h> #include <string.h> #include <stdlib.h> #include <iostream&

NYOJ 237 游戏高手的烦恼 &amp;&amp; POJ3041-Asteroids ( 二分图的最大匹配 )

链接: NYOJ 237  游戏高手的烦恼:click here~~ POJ  3041 Asteroids           :click here~~ 题意: 两题一样,翻译不同而已. 有一位传说级游戏高手,在闲暇时间里玩起了一个小游戏,游戏中,一个n*n的方块形区域里有许多敌人,玩家可以使用炸弹炸掉某一行或者某一列的所有敌人.他是种玩什么游戏都想玩得很优秀的人,所以,他决定,使用尽可能少的炸弹炸掉所有的敌人. 现在给你一个游戏的状态,请你帮助他判断最少需要多少个炸弹才能炸掉所有的敌人吧.

NYOJ 49 开心的小明

开心的小明 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 小明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N 元钱就行".今天一早小明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N 元.于是,他把每件物品规定了一个重要度,分为5 等:用整数1~5 表示,第5 等最重要.他还从因特网上查到了每件物品的价格(都是整数元).

NYOJ 106 背包问题

背包问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v,w<=10):如果给你一个背包它能容纳的重量为m(10<=m<=20),你所要做的就是把物品装到背包里,使背包里的物品的价值总和最大. 输入 第一行输入一个正整数n(1<=n<=5),表示有n组测试数据: 随后有n测试数据,每组测试数据的第一行有两个正整数s,m(1<=s<=10

NYOJ 289 苹果

苹果 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 ctest有n个苹果,要将它放入容量为v的背包.给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值. 输入 有多组测试数据,每组测试数据第一行为2个正整数,分别代表苹果的个数n和背包的容量v,n.v同时为0时结束测试,此时不输出.接下来的n行,每行2个正整数,用空格隔开,分别代表苹果的大小c和价钱w.所有输入数字的范围大于等于0,小于等于1000. 输出 对每组测试数据输出一个整数,代表能放入背包的苹

nyoj 括号匹配

这个方程有两种形式,本文采用 if(s[i]=s[j]) dp[i][j]=d[i-1][j-1] dp[i][j]=min(dp[i][k]+dp[k+1][j],dp[i][j]) (i=<k<j) 其实与另一种方法比较:根据j的所有匹配情况取最小值 1.i到j无匹配,取为dp[i][j-1]+1 2.列举所有匹配情况 dp[i][k-1]+dp[k+1][j] 取上述所有情况最小值 两者都能获得正确的结果. 同时两者的初始化为 dp[i][j]==1 if(i==j) 规划方向为: