您的位置:首页 > 其它

空间人物行走的向量实现(pku1835解题报告)

2010-07-17 16:46 381 查看
可以先看这道题目中的描述http://acm.pku.edu.cn/JudgeOnline/problem?id=1835

首先讨论数据结构。

由于我们的问题是在三维坐标下的,于是我们首先建立三维坐标下的数据结构三维向量类,为方便其运算同时封装它需要的运算。

struct vector3 {
int x, y, z;
vector3 operator *(vector3 b) {
vector3 ans;
ans.x = y * b.z - z * b.y;
ans.y = z * b.x - x * b.z;
ans.z = x * b.y - y * b.x;
return ans;
}
vector3 operator *(int k) {
vector3 ans;
ans.x = x*k;
ans.y = y*k;
ans.z = z*k;
return ans;
}
vector3 operator +=(vector3 b) {
x += b.x;
y += b.y;
z += b.z;
return *this;
}
};


第一个运算符*是向量的叉积,叉积的运算如右图所示,叉积不符合交换律。

第二个运算符*是向量的延长,这里主要用于产生位移向量。

第三个运算符+=是加上另一个向量。

对于空间内一个人,
比如航天员
astronaut,
他要完成前后左右转,那么就需要一个变量表示他的面朝哪边后文称面向量,他要完成上下转我们还需要知道哪个方向对他来说是上,于是我们还需要一个向量表示他的头朝哪边后文称为头向量,同时我们还必须一个向量来表示他在空间中的位置后文称位置向量。现在我们总共需要三个向量:面向量,头向量,位置向量。用f(face)h(head)pos(position)表示。

struct people {
vector3 f, h, pos;
} astronaut;


然后我们讨论基于这个数据结构完成的上下左右前后转动的算法。

前进不需要转动,后退只需要把面向量乘以-1即可。

下面讨论左右上下转动。



如图,假设a向量为头向量,b向量为面向量,那么我们可以发现a*b就是他左转以后的面向量,b*a就是他右转以后的面向量,而左右转的时候头向量是不变的。

向上与向下也很简单,向上转动以后,头朝着之前面向量相反的方向。面朝着之前的头的方向。

向下转动,头朝着之前的面向量,面朝着之前头向量的相反方向。程序实现的时候要注意转之前与转之后变量的变化与使用。

转动完了以后就讨论行走了。

由于面向量使用单位向量,于是转动以后的行走多少单位就是面向量乘以多少,这个叫做位移向量,位置向量加上位移向量就完成了一次行走了。

这里注意产生位移向量的时候要保证面向量是单位向量,由于这道题的转动都是直角转动,且面向量与头向量垂直,所以叉乘以后的向量模|a||b|sin90还是1可以直接拿来用


下面是行走的算法,cmd表示指令,m表示距离。astronaut是people类的全局变量,在people类的定义后声明过了。

void walk(char* cmd, int m) {
if (strcmp(cmd,"left")==0){
astronaut.f = astronaut.h * astronaut.f;
astronaut.pos += astronaut.f*m;
}
if (strcmp(cmd,"right")==0) {
astronaut.f = astronaut.f * astronaut.h;
astronaut.pos += astronaut.f*m;
}
if (strcmp(cmd,"forward")==0)
astronaut.pos += astronaut.f * m;
if (strcmp(cmd,"back")==0) {
astronaut.f = astronaut.f*-1;
astronaut.pos += astronaut.f*m;
}
if (strcmp(cmd,"up")==0) {
vector3 oldh = astronaut.h;
astronaut.h=astronaut.f*-1;
astronaut.f=oldh;
astronaut.pos += astronaut.f*m;
}
if (strcmp(cmd,"down")==0) {
vector3 oldh = astronaut.h;
astronaut.h=astronaut.f;
astronaut.f=oldh*-1;
astronaut.pos += astronaut.f*m;
}
}


我这里为方便起见使用了右手螺旋坐标,而题目上是左手螺旋坐标,在输出时需要简单处理一下,只需改变一下y轴符号即可,下面是main函数。

int main(int argc, char** argv) {
char cmd[10];
int t, n, m, i, face;
scanf("%d",&t);
while (t--) {
astronaut.h.x = astronaut.h.y =
astronaut.f.z = astronaut.f.y =
astronaut.pos.x = astronaut.pos.y = astronaut.pos.z = 0;
astronaut.h.z = astronaut.f.x = 1;
scanf("%d",&n);
while (n--) {
scanf("%s%d",cmd,&m);
walk(cmd, m);
}
if (astronaut.f.x > 0)face = 0;
if (astronaut.f.x < 0)face = 3;
if (astronaut.f.y < 0)face = 1;
if (astronaut.f.y > 0)face = 4;
if (astronaut.f.z > 0)face = 2;
if (astronaut.f.z < 0)face = 5;
printf("%d %d %d %d/n",astronaut.pos.x,-astronaut.pos.y,astronaut.pos.z,face);
}
return (EXIT_SUCCESS);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: