目录
斜转魔方
1,魔方三要素
(1)组成部件
8个角块和6个中心块
把8个角块编号12345678,分别对应上层的左上、右上、左下、右下以及下层的。

(2)可执行操作
斜转魔方既可以理解成四轴魔方,也可以理解成八轴魔方。
如果认为是8种操作的话,那么可以分成四组,任意一组的2个操作各执行1次或2次加起来都相当于魔方整体旋转。
按照4种操作理解的话,每种操作都会改变3个角块的位置,另外5个角块位置不变,这4个操作影响的3个角块分别是:167、258、358、467
(3)目标态
(3.1)形状
任意一次操作之后,魔方都是正方体,最后也自然是正方体。
(3.2)颜色
8个角块可以唯一确定6个面的位置关系。
2,复原方法
(1)调整8个角块位置
先调整4个角块的位置,此时可能出现的情况,可以用bfs算一下:
cpp
string f1(string s)
{
char c = s[3];
s[3] = s[6], s[6] = s[5], s[5] = c;
return s;
}
string f2(string s)
{
char c = s[2];
s[2] = s[4], s[4] = s[7], s[7] = c;
return s;
}
string f3(string s)
{
char c = s[0];
s[0] = s[6], s[6] = s[5], s[5] = c;
return s;
}
string f4(string s)
{
char c = s[1];
s[1] = s[4], s[4] = s[7], s[7] = c;
return s;
}
void bfs()
{
string s = "12345678";
queue<string>q;
q.push(s);
map<string, int>m;
m[s] = 1;
while (!q.empty())
{
string str = q.front();
q.pop();
string s = f1(str);
if (!m[s])m[s] = 1, q.push(s);
s = f2(str);
if (!m[s])m[s] = 1, q.push(s);
s = f3(str);
if (!m[s])m[s] = 1, q.push(s);
s = f4(str);
if (!m[s])m[s] = 1, q.push(s);
}
for (auto mi : m) {
bool flag = true;
for (int i = 0; i < 4; i++)if (mi.first[i]>'4')flag=false;
if(flag)cout << mi.first << endl;
}
}
输出:
12345678
13248675
42315768
43218765
所以,只需要上层是1234,下层就一定是5678
这一步非常简单,不需要任何公式。
(2)调整6个中心块位置
以8、5、3为轴顺时针各一次,8个角块的位置不变,左下中心块互换,另外4个中心块轮换。
为了方便,我们把这个叫做853操作。
把6个中心块编号为1上2下3前4后5左6右,则853操作对中心块的位置影响是123456->451623
另外3个操作(674、582、761)的影响依次是532641、365142、645213
于是我们可以就可以推导中心块调整位置的公式:
cpp
string f1(string s)
{
char c = s[2];
s[2] = s[5], s[5] = c;
c = s[1];
s[1] = s[4], s[4] = s[6], s[6] = s[3], s[3] = c;
return s;
}
string f2(string s)
{
char c = s[2];
s[2] = s[3], s[3] = c;
c = s[1];
s[1] = s[5], s[5] = s[4], s[4] = s[6], s[6] = c;
return s;
}
string f3(string s)
{
char c = s[2];
s[2] = s[6], s[6] = c;
c = s[1];
s[1] = s[3], s[3] = s[5], s[5] = s[4], s[4] = c;
return s;
}
string f4(string s)
{
char c = s[2];
s[2] = s[4], s[4] = c;
c = s[1];
s[1] = s[6], s[6] = s[3], s[3] = s[5], s[5] = c;
return s;
}
void bfs()
{
string s = " 123456";
queue<string>q;
q.push(s);
map<string, int>m;
m[s] = 1;
while (!q.empty())
{
string str = q.front();
q.pop();
string s = f1(str);
if (!m[s])m[s] = 1, q.push(s);
s = f2(str);
if (!m[s])m[s] = 1, q.push(s);
s = f3(str);
if (!m[s])m[s] = 1, q.push(s);
s = f4(str);
if (!m[s])m[s] = 1, q.push(s);
}
for (auto mi : m) {
int x = 0;
for (int i = 0; i < 7; i++)if (mi.first[i]==s[i])x++;
if(x>=4)cout << mi.first << endl;
}
}
输出:
123456
123564
123645
124536
124653
125346
125463
126354
126435
134256
135426
136452
142356
143526
143652
152436
153246
153462
162453
163254
163425
231456
243156
253416
263451
312456
324156
325416
326451
413256
421356
423516
423651
513426
521436
523146
523461
613452
621453
623154
623415
理论上任选一个都可以作为基础公式模式。
为了方便,我们选143526作为公式模式。
代码略改一下,求出123456到143526的变换路径:
cpp
void bfs()
{
string s = " 123456";
queue<string>q;
q.push(s);
map<string, int>m;
map<string, string>p;
map<string, int>p2;
m[s] = 1;
while (!q.empty())
{
string str = q.front();
q.pop();
string s = f1(str);
if (!m[s])m[s] = 1, q.push(s), p[s] = str, p2[s] = 1;
s = f2(str);
if (!m[s])m[s] = 1, q.push(s), p[s] = str, p2[s] = 2;
s = f3(str);
if (!m[s])m[s] = 1, q.push(s), p[s] = str, p2[s] = 3;
s = f4(str);
if (!m[s])m[s] = 1, q.push(s), p[s] = str, p2[s] = 4;
}
s = " 143526";
while (s != " 123456") {
cout << s<<" "<<p2[s] << " ";
s = p[s];
}
cout << s << endl;
}
输出:
143526 2 634215 1 415632 3 624351 1 451623 1 123456
也就是说,从123456,依次执行853、853、582、853 、674操作,共15次操作,即可变成143526,即245三个色块的轮换。
有此公式,即可完成所有中心块的归位。
亲测有效:

会不会出现只有2个面的颜色反过来的情况呢?不会
首先,如果会出现只有2个面的颜色反过来的情况,那就一定会出现123456变成123546,即012345变成012435,且一定是只需要4个操作的组合就可以达成。(这一步的推理已经考虑了整个魔方旋转的场景)
其次,用程序枚举:
cpp
int main()
{
CubeBlock block1(0, 6);//6中心块
vector<CubeBlock>b = vector<CubeBlock>{ block1 };
Opt opt1{ { {3,1,2,4,0,5}} ,"左上" };
Opt opt2{ { {3,1,2,5,4,0} } ,"右上" };
Opt opt3{ { {2,1,4,3,0,5} } ,"左下" };
Opt opt4{ { {2,1,5,3,4,0} } ,"右下" };
CubeOpt op1(b, opt1);
CubeOpt op2(b, opt2);
CubeOpt op3(b, opt3);
CubeOpt op4(b, opt4);
vector<CubeOpt>opts = { op1,op2,op3,op4 };
for (int i = 0; i < opts.size(); i++)mans[i] = opts[i].getName();
Cube cube(b, opts);
cube.bfs(0, 1, 2);
return 0;
}
输出:k=60
果然不存在这种场景
(3)调整角块方向
把853操作直接重复4遍,则所有块位置不变,角块中24方向不变,其他6个角块都顺时针转一次。
我们把它理解成对8个角块顺时针旋转,并对24逆时针旋转,把这个操作叫做24操作。
2个12操作+1个24操作,我们就得到一个只改变1和4不改变另外6个角块的操作(1顺时针旋转4逆时针旋转)。
有了这个操作,显然可以把除了2个相邻角块之外的所有角块方向复原。
最后,有没有可能只有2个相邻角块方向不对呢?应该不可能。
至此,魔方复原

斜转扭曲魔方
1,魔方三要素
和斜转魔方唯一的区别就是,有4个中心块(蓝绿红橙)是扭曲的,也就是要区分朝向了。
2,中心块朝向奇偶性
我们把中心块旋转0度和180度叫偶状态,旋转90度和270度叫奇状态。
根据若干次尝试,我提出1个定理和1个猜想:
(1)定理:如果6个中心块的位置复原,无论角块的位置和朝向,6个中心块一定都是偶状态。
用斜转魔方证明这个定理可能还不容易想出来,但是用斜转扭曲魔方证明就很容易了。
扭曲中心块是双色的,分界线是一条线段,延长之后刚好经过正方体的2个顶点。对顶点进行2染色,即可推导出中心块朝向的奇偶性。
(2)猜想:如果位置没有完全复原但是满足对立色,即6个中心块的位置是整个魔方成镜面,无论角块的位置和朝向,6个中心块一定都是奇状态。
这个猜想应该是对的,但是这里我不做证明。
基于(1),斜转扭曲魔方相对于斜转魔方,唯一需要多做的事情就是4个扭曲中心块中的若干个需要旋转180度。
3,复原方法
(1)调整8个角块位置
同斜转魔方
(2)调整6个中心块位置
同斜转魔方
(3)调整角块方向
同斜转魔方

因为4个扭曲中心块都是偶状态,所以形态是没问题的,只有颜色可能对不上。
(4)调整中心块朝向
上文有提到24操作,即把853操作直接重复4遍,则所有块位置不变,角块中24方向不变,其他6个角块都顺时针转一次。
我们定义一个242424操作,即853操作重复12遍,效果是所有块位置不变,所有角块朝向不变,25号中心块朝向不变,1346号中心块朝向旋转180度。
根据扭曲中心块需要调整朝向的数量,分为0 1 2 3 4这5种情况,4->1->2->3->0之间的转化都刚好是1个242424操作。
至此,魔方复原