3.骰子涂色(UVA253)

3.骰子涂色(UVA253)利用旋转矩阵求解

题目简单分析

题目的详细内容可以在这个网站上看到,下面简单说明一下题目要求。
[题意]
本题给出两颗六面涂色(r、g、b三种颜色)的骰子。需要解决的问题是判断其中一颗骰子能否通过旋转得到另一颗骰子。

[输入输出]
样例输入如下:每行给出12个字符,前6个字符和后6个字符分别是两颗骰子的涂色(按照下图顺序排列)。

程序只需要输出判断的结果即可(TRUE/FALSE)。
Sample Input

rbgggrrggbgr
rrrbbbrrbbbr
rbgrbgrrrrrg

Sample Output

TRUE
FALSE
FALSE

[分析]
本题主要解决的问题是骰子的旋转,可以通过固定一个轴,枚举可能的情况来对所有情况进行判断,网上已经又许多类似的解法了。这里我通过矩阵的方法来模拟骰子的旋转,可以通过旋转矩阵求解得出所有的结果,然后将求解的结果与另一颗骰子的颜色进行比较得出结果。下面是分别绕三个轴进行旋转的矩阵:

将三个矩阵相乘可以得到如下矩阵(注意矩阵为左乘,这里采用了3-1-2欧拉角的形式):

将旋转矩阵作用于骰子的姿态矩阵,可以得到骰子旋转之后的姿态;通过遍历各个旋转角度得到骰子可能的旋转结果,然后将旋转结果与另一枚骰子进行比较,如果相同则说明两枚骰子的涂色是相同的,否则涂色不同。

代码

代码中需要注意的有以下几点:
1.由于旋转的角度为90度的整数倍,可以通过自定义三角函数来减少计算复杂度。
2.需要自定义矩阵乘法
3.骰子的涂色与姿态矩阵之间的转换
完整代码如下,用C语言实现,VS2017的工程在github。代码如有bug,敬请指出。

#include <stdio.h>
#include <string.h>
char temp[12];
char a[6], b[6];//保存输入
int R[3][3];//旋转矩阵
int Sin(int a);
int Cos(int a);
void updateR(int pitch, int roll, int yaw);
void Rotate(char c[6]);
int main() {
	int flag = 0;
	while (scanf("%s", temp) != EOF) {
		memcpy(b, temp + 6, 6 * sizeof(char));
		flag = 0;
		for (int i = 0; i < 360; i += 90)
			for (int j = 0; j < 360; j += 90)
				for (int k = 0; k < 360; k += 90) {
					memcpy(a, temp, 6 * sizeof(char));
					updateR(i, j, k);
					Rotate(a);
					if (strcmp(a, b) == 0) {
						flag = 1;i = j = k = 360;
					}
				}
		if (flag) printf("TRUE\n");
		else printf("FALSE\n");
	}
	return 0;
}
void Multi(int r[3][3], int m[3][6], int a[3][6]) {//矩阵乘法
	for (int i = 0; i < 3; ++i)
		for (int j = 0; j < 6; ++j) {
			a[i][j] = r[i][0] * m[0][j] + r[i][1] * m[1][j] + r[i][2] * m[2][j];
		}
}
void Rotate(char c[6]) {//旋转
	int Mat[3][6] = { 0 }, Ret[3][6] = { 0 };
	//矢量转矩阵
	Mat[2][0] = c[0]; Mat[0][1] = c[1]; Mat[1][2] = -c[2];
	Mat[1][3] = c[3]; Mat[0][4] = -c[4]; Mat[2][5] = -c[5];
	//旋转矩阵作用于矩阵
	Multi(R, Mat, Ret);
	for (int i = 0; i < 6; ++i) {
		if (Ret[2][i] > 0) c[0] = Ret[2][i];
		else if (Ret[0][i] > 0) c[1] = Ret[0][i];
		else if (Ret[1][i] < 0) c[2] = -Ret[1][i];
		else if (Ret[1][i] > 0) c[3] = Ret[1][i];
		else if (Ret[0][i] < 0) c[4] = -Ret[0][i];
		else if (Ret[2][i] < 0) c[5] = -Ret[2][i];
	}
}
void updateR(int pitch, int roll, int yaw) {//更新旋转矩阵
	//3-1-2旋转矩阵(Z-X-Y)
	R[0][0] = Cos(pitch)*Cos(yaw) - Sin(roll)*Sin(pitch)*Sin(yaw);
	R[0][1] = Cos(pitch)*Sin(yaw) + Sin(roll)*Sin(pitch)*Cos(yaw);
	R[0][2] = -Cos(roll)*Sin(pitch);
	R[1][0] = -Cos(roll)*Sin(yaw);
	R[1][1] = Cos(roll)*Cos(yaw);
	R[1][2] = Sin(roll);
	R[2][0] = Sin(pitch)*Cos(yaw) + Sin(roll)*Cos(pitch)*Sin(yaw);
	R[2][1] = Sin(pitch)*Sin(yaw) - Sin(roll)*Cos(pitch)*Cos(yaw);
	R[2][2] = Cos(roll)*Cos(pitch);
}
//为了简化三角运算,自定义三角函数如下
int Sin(int a) {//a的取值应为0、90、180、270
	if (a == 90) return 1;
	else if (a == 270) return -1;
	else return 0;
}
int Cos(int a) {//a的取值应为0、90、180、270
	if (a == 0 || a == 360) return 1;
	else if (a == 90 || a == 270) return 0;
	else return -1;
}



猜你喜欢

转载自blog.csdn.net/weixin_43374723/article/details/83478788
3.