笔试被虐惨,选择题一半多的概率题,每道题差不多3、5分钟,so,最后好几个没有算。
附加两个大题,一个是编写魔方,另一个是机器学习的分布不均衡问题和SVM。魔方题没有写完,机器学习的题目也只答了一问...
当天晚上把魔方的代码完善了下,没有找到好的解法,硬写的,麻烦的要死。
晚上的时候网上已经有题目了,详情如下,最后结果的输出其实不一定要与题目一致,因为每一面的方向没有明确定义,颜色对了即可,比如本文的程序里,Y面与题目的Y面相差180度:
一个三阶魔方由六个面组成,颜色分别是白色(W)、对面为黄色(Y)、红色(R)、对面为橙色(O)、绿色(G)、对面为蓝色(B)。如果手持魔方,白色向上,红色朝向自己,则绿色在左手侧。
请写一个程序,对一个处于还原状态(各面各块同色)的魔方,进行操作,打印操作后的魔方状态。操作指令为单个操作指令组成的字符串。单个操作指令包括:
1)U:白色面顺时针旋转90度
2)D:黄色面顺时针旋转90度
3)F:红色面顺时针旋转90度
4)B:橙色面顺时针旋转90度
5)L:绿色面顺时针旋转90度
6)R:蓝色面顺时针旋转90度
其中顺时针旋转定义为将该面朝向自己时的顺时针方向。
按WYROGB的顺序输出经过操作后6个面的状态。每个面首先输出中心块颜色,然后从此面面向自己时的左下角块开始,顺时针顺出每块的颜色。输出一面后换行。
请设计一个数据结构表示魔方,并基于该数据结构完成功能。
请用C/C++,Java或Python语言实现。请注意尽量以可成功编译或可直接运行为标准来编写代码。
示例:
输入:
LR
输出:
WOOOWRRRW
YRRRYOOOY
RWWWRYYYR
OYYYOWWWO
GGGGGGGGG
BBBBBBBBB
代码如下:
#include <stdio.h>
#include <stdlib.h>
struct panel {
//暴力解法,每个面的面板颜色和四个接触的边
int a[3][3]; //每个面的颜色
char status; //本面的颜色符号
struct panel *u; //四个相邻的面
int ul; //相邻的边是相应面的那一条1-6表示1-3行+1-3列,-号表示逆序
struct panel *r;
int rl;
struct panel *d;
int dl;
struct panel *l;
int ll;
};
typedef struct panel PP;
void initPanel(PP *p, int color);
void changePanel(PP *p, PP *u, PP *r, PP *d, PP *l);
void rot(PP *p);
void getLine(PP *p,int line,int b[]);
void setLine(PP *p,int line ,int b[]);
int abValue(int x);
void printPanel(PP *p, int check);
char intTochar(int i);
void printA(int a[]);
int main(int argc, char **argv)
{
char c;
PP Wp;
PP Op;
PP Bp;
PP Rp;
PP Gp;
PP Yp;
//定义每个面的颜色
initPanel(&Wp,1);
initPanel(&Op,2);
initPanel(&Bp,3);
initPanel(&Rp,4);
initPanel(&Gp,5);
initPanel(&Yp,6);
/*给白色面定义四个临边,尼玛太麻烦了,有好一点的算法没?
以这个方向定义,输出也是用的这个方向
---
| O |
--- --- --- ---
| G | W | B | Y |
--- --- --- ---
| R |
---
*/
Wp.status = 'W';
Wp.u = &Op;
Wp.ul = 3;
Wp.r = &Bp;
Wp.rl = 4;
Wp.d = &Rp;
Wp.dl = 1;
Wp.l = &Gp;
Wp.ll = 6;
//橘色定义
Op.status = 'O';
Op.u = &Yp;
Op.ul = -1;
Op.r = &Bp;
Op.rl = -1;
Op.d = &Wp;
Op.dl = 1;
Op.l = &Gp;
Op.ll = 1;
//蓝色定义
Bp.status = 'B';
Bp.u = &Op;
Bp.ul = -6;
Bp.r = &Yp;
Bp.rl = 4;
Bp.d = &Rp;
Bp.dl = 6;
Bp.l = &Wp;
Bp.ll = 6;
//红色定义
Rp.status = 'R';
Rp.u = &Wp;
Rp.ul = 3;
Rp.r = &Bp;
Rp.rl = 3;
Rp.d =&Yp;
Rp.dl = -3;
Rp.l = &Gp;
Rp.ll = -3;
//绿色定义
Gp.status = 'G';
Gp.u = &Op;
Gp.ul = 4;
Gp.r = &Wp;
Gp.rl = 4;
Gp.d = &Rp;
Gp.dl = -4;
Gp.l = &Yp;
Gp.ll = 6;
//黄色定义
Yp.status = 'Y';
Yp.u = &Op;
Yp.ul = -1;
Yp.r = &Gp;
Yp.rl = 4;
Yp.d = &Rp;
Yp.dl = -3;
Yp.l = &Bp;
Yp.ll = 6;
while((c = getchar()) != '\n'){
if(c == 'U')
changePanel(&Wp, Wp.u, Wp.r, Wp.d, Wp.l); //改变本面和相邻的四个面
if(c == 'D')
changePanel(&Yp, Yp.u, Yp.r, Yp.d, Yp.l);
if(c == 'F')
changePanel(&Rp, Rp.u, Rp.r, Rp.d, Rp.l);
if(c == 'B')
changePanel(&Op, Op.u, Op.r, Op.d, Op.l);
if(c == 'L')
changePanel(&Gp, Gp.u, Gp.r, Gp.d, Gp.l);
if(c == 'R')
changePanel(&Bp, Bp.u, Bp.r, Bp.d, Bp.l);
}
//输出每一个面,注意输出的顺序,1代表与定义顺序一致,0代表翻转180
printPanel(&Wp, 1);
printPanel(&Yp, 0);
printPanel(&Rp, 1);
printPanel(&Op, 1);
printPanel(&Gp, 1);
printPanel(&Bp, 1);
return 0;
}
//初始每个面的颜色
void initPanel(PP *p, int color){
int i,j;
for(i = 0;i < 3;i++)
for(j = 0;j < 3;j++)
p->a[i][j] = color;
}
//旋转
void changePanel(PP *p, PP *u, PP *r, PP *d, PP *l){
//旋转本面二维数组
rot(p);
//旋转四个边
int ua[3],ra[3],da[3],la[3];
int i,j;
getLine(p->u,p->ul,ua);
getLine(p->r,p->rl,ra);
getLine(p->d,p->dl,da);
getLine(p->l,p->ll,la);
//输出本面的当前四个边
printf("%c %dth is\n",p->u->status,p->ul);
printA(ua);
printf("%c %dth is\n",p->r->status,p->rl);
printA(ra);
printf("%c %dth is\n",p->d->status,p->dl);
printA(da);
printf("%c %dth is\n",p->l->status,p->ll);
printA(la);
printf("\n");
//转换4条边,由于下边和左边的定义顺序是左到右、上到下排列,与顺时针方向相反,在转换时要注意
for(i = 0;i < 3;i++){
j = ua[i];
ua[i] = la[2-i];
la[2-i] = da[2-i];
da[2-i] = ra[i];
ra[i] = j;
}
//输出旋转后本面的当前四个边
printf("%c %d th is\n",p->u->status,p->ul);
printA(ua);
printf("%c %d th is\n",p->r->status,p->rl);
printA(ra);
printf("%c %d th is\n",p->d->status,p->dl);
printA(da);
printf("%c %d th is\n",p->l->status,p->ll);
printA(la);
printf("\n");
//将旋转后的4个边赋值给相应的临面
setLine(p->u,p->ul,ua);
setLine(p->r,p->rl,ra);
setLine(p->d,p->dl,da);
setLine(p->l,p->ll,la);
}
//旋转二维数组,注意每一行交换两个
void rot(PP *p){
int i,j;
for(i = 0; i < 2; i++){
j = p->a[0][i];
p->a[0][i] = p->a[2-i][0];
p->a[2-i][0] = p->a[2][2-i];
p->a[2][2-i] = p->a[i][2];
p->a[i][2] = j;
}
}
//获取面的某条边数据
void getLine(PP *p,int line,int b[]){
int i;
if(abValue(line) < 4){
for(i = 0;i < 3;i++){
if(line < 0)
b[i] = p->a[abValue(line) - 1][2-i];
if(line > 0)
b[i] = p->a[line - 1][i];
}
}
else if(abValue(line) >= 4){
for(i = 0;i < 3;i++){
if(line < 0)
b[i] = p->a[2-i][abValue(line) - 4];
if(line > 0)
b[i] = p->a[i][line - 4];
}
}
}
//赋值面的某条边
void setLine(PP *p,int line ,int b[]){
int i;
if(abValue(line) < 4){
for(i = 0;i < 3;i++){
if(line < 0)
p->a[abValue(line) - 1][2-i] = b[i];
if(line > 0)
p->a[line - 1][i] = b[i];
}
}
else if(abValue(line) >= 4){
for(i = 0;i < 3;i++){
if(line < 0)
p->a[2-i][abValue(line) - 4] = b[i];
if(line > 0)
p->a[i][line - 4] = b[i];
}
}
}
//取绝对值
int abValue(int x){
if(x < 0)
return 0-x;
else
return x;
}
//check为定义如何输出,定义每一面时是按照正方体展开的方向,最下面的Y貌似与定义顺序不同
void printPanel(PP *p, int check){
int i,j,k;
if(check == 1){
//正序,j+k*正序下标,无变化
j = 0;
k = 1;
}
else if(check == 0){
//逆序下标=2-正序下标 j+k*正序下标
j = 2;
k = -1;
}
//输出二维数组,先输出中心点,再输出4个边,左下开始顺时针
printf("%c",intTochar(p->a[1][1]));
for(i = 0;i < 2;i++)
printf("%c",intTochar(p->a[j+k*(2-i)][j+k*0]));
for(i = 0;i < 2;i++)
printf("%c",intTochar(p->a[j+k*0][j+k*i]));
for(i = 0;i < 2;i++)
printf("%c",intTochar(p->a[j+k*i][j+k*2]));
for(i = 0;i < 2;i++)
printf("%c",intTochar(p->a[j+k*2][j+k*(2-i)]));
printf("\n");
}
//由数字颜色转为字符
char intTochar(int i){
switch(i){
case 1:
return 'W';
break;
case 2:
return 'O';
break;
case 3:
return 'B';
break;
case 4:
return 'R';
break;
case 5:
return 'G';
break;
case 6:
return 'Y';
break;
default:
return 'N';
break;
}
}
//输出暂存数组
void printA(int a[]){
printf("%c",intTochar(a[0]));
printf("%c",intTochar(a[1]));
printf("%c",intTochar(a[2]));
printf("\n");
}