目录
一,背景
二,实现思路
1,开放式的分组和编号方案
2,求解目标
三,V1代码(DFS)
四,开放式尝试
在第一次自己写代码推导魔方公式(四轴斜转魔方)之后,我决定写一个更通用的推导公式的代码。
输入:魔方的三要素,即部件、操作、目标
输出:操作序列
分组方案需要最基本的魔方基础,比如角块为一组,棱块为一组,中心块为一组。
这些组分别编号第0组,第1组,第2组......具体怎么对应是开放的。
对于每一组,各个块的编号分别为0,1,2......具体怎么对应是开放的。
求解目标一定是只有一组块交换位置,其他组的所有块位置不变。
为了方便打印路径,我采用了DFS
template
class GetSingleId
{
public:
int id(T x)
{
auto it = m.find(x);
if (it != m.end())return it->second;
return m[x] = n++;
}
int num()
{
return n;
}
private:
mapm;
int n = 0;
};
template
class GetCombineId
{
public:
vector combineId(vector& x)
{
if (v.empty())v.resize(x.size());
vectorans(x.size());
for (int i = 0; i < x.size(); i++)ans[i] = v[i].id(x[i]);
return ans;
}
int id(vector& x)
{
return v2.id(combineId(x));
}
int num()
{
return v2.num();
}
vector>v;
GetSingleId>v2;
};
struct CubeBlock
{
int typeId;//角块,棱块等,分组id
vectorv;//一组块
CubeBlock(int id, int n)
{
typeId = id;
v.resize(n);
for (int i = 0; i < n; i++)v[i] = i;//每一组的块都按从0开始编号
}
int changeNum()
{
int ans = 0;
for (int i = 0; i < v.size(); i++)if (v[i] != i)ans++;
return ans;
}
bool isOk()
{
return changeNum() == 0;
}
bool operator<(const CubeBlock& blocks)const
{
for (int i = 0; i < v.size() && i < blocks.v.size(); i++) {
if (v[i] < blocks.v[i])return true;
if (blocks.v[i] < v[i])return false;
}
return false;
}
};
class CubeOpt
{
public:
CubeOpt(vector& b, vector>& v) :b{ b }, v{ v }{}//若干组块及其变换
CubeOpt& operator =(const CubeOpt& opt) {
b = opt.b, v = opt.v;
return *this;
}
void change()
{
for (int i = 0; i < v.size(); i++) {
change(b[i], v[i]);
}
}
void reback()
{
for (int i = 0; i < v.size(); i++) {
reback(b[i], v[i]);
}
}
private:
void change(CubeBlock& b, vector& v)//一组块及一个变换,如v[1]=2表示把2号块移到1号块的位置
{
vectorbv = b.v;
for (int i = 0; i < v.size(); i++) {
b.v[i] = bv[v[i]];
}
}
void reback(CubeBlock& b, vector& v)
{
vectorbv = b.v;
for (int i = 0; i < v.size(); i++) {
b.v[v[i]] = bv[i];
}
}
vector>& v;
vector& b;
};
class Cube
{
public:
Cube(vector& b, vector& opts) :b{ b }, opts{ opts }{}
bool dfs(int targetId, int difNumLow, int difNumHigh)//推导出一个公式
{
if (m.id(b) != m.num() - 1)return false;
if (ok(targetId, difNumLow, difNumHigh))return true;
for (int i = 0; i < opts.size(); i++) {
auto& opt = opts[i];
opt.change();
if (dfs(targetId, difNumLow, difNumHigh)) {
cout << i << " ";
return true;
}
opt.reback();
}
return false;
}
private:
bool ok(int targetId, int difNumLow, int difNumHigh)
{
for (int i = 0; i < b.size(); i++) {
int c = b[i].changeNum();
if (i != targetId) {
if (c)return false;
}
else {
if (c < difNumLow || c > difNumHigh)return false;
}
}
return true;
}
vector&b;
vector&opts;
GetCombineIdm;
};
先以金字塔二重奏魔方为例:
int main()
{
CubeBlock block1(0, 4);//4角块
CubeBlock block2(1, 4);//4棱块
vectorb = vector{ block1,block2 };
vector>v1 = { {0,1,2,3},{1,2,0,3} };
vector>v2 = { {0,1,2,3},{3,0,2,1} };
vector>v3 = { {0,1,2,3},{0,3,1,2} };
vector>v4 = { {0,1,2,3},{2,1,3,0} };
CubeOpt op1(b, v1);
CubeOpt op2(b, v2);
CubeOpt op3(b, v3);
CubeOpt op4(b, v4);
vectoropts = { op1,op2,op3,op4 };
Cube(b, opts).dfs(1, 4, 4);
return 0;
}
输出:
1 0 0(注意,输出的是倒着的,要按照001的顺序执行)
虽然并没有得到上面公式,但是这个结果是对的。
再用四轴旋转魔方试一下:
int main()
{
CubeBlock block1(0, 8);//8角块
CubeBlock block2(1, 6);//6棱块
vectorb = vector{ block1,block2 };
vector>v1 = { {0,3,2,6,4,5,1,7},{2,1,5,3,4,0} };
vector>v2 = { {2,1,5,3,4,0,6,7},{5,1,2,0,4,3} };
vector>v3 = { {0,4,2,1,3,5,6,7},{3,1,2,4,0,5} };
vector>v4 = { {7,1,0,3,4,5,6,2},{4,1,0,3,2,5} };
CubeOpt op1(b, v1);
CubeOpt op2(b, v2);
CubeOpt op3(b, v3);
CubeOpt op4(b, v4);
vectoropts = { op1,op2,op3,op4 };
Cube(b, opts).dfs(1, 1, 6);
return 0;
}
输出1 0 0 1 0 0 1 0 0
这相当于是一个6步的公式,把这个公式重复3遍就得到一个公式,它的效果是把一个四轴旋转魔方的前面和下面中心块交换,后面和右面中心块交换,其他块不变。
再拿233魔方试一下:
int main()
{
CubeBlock block1(0, 8);//8角块
CubeBlock block2(1, 8);//8棱块
vectorb = vector{ block1,block2 };
vector>v1 = { {3,0,1,2,4,5,6,7},{3,0,1,2,4,5,6,7} };
vector>v2 = { {0,6,5,3,4,2,1,7},{0,5,2,3,4,1,6,7} };
vector>v3 = { {0,1,7,6,4,5,3,2},{0,1,6,3,4,5,2,7} };
vector>v4 = { {7,1,2,4,3,5,6,0},{0,1,2,7,4,5,6,3} };
vector>v5 = { {5,4,2,3,1,0,6,7},{4,1,2,3,0,5,6,7} };
CubeOpt op1(b, v1);
CubeOpt op2(b, v2);
CubeOpt op3(b, v3);
CubeOpt op4(b, v4);
CubeOpt op5(b, v5);
vectoropts = { op1,op2,op3,op4,op5 };
Cube(b, opts).dfs(1, 1, 4);
return 0;
}
输出 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0
倒也算是一个公式,但是影响了5个棱块,不便于使用。
于是我们收紧搜索范围:Cube(b, opts).dfs(1, 1, 4);
输出
2 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 2 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 2 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0
这显然有点长,但是我们可以提取出
1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0
看看它的效果是啥,我们很快就发明了一个交换三个棱块的公式。
然而,这还不够,我们需要的是指交换2个块的公式。
注意到上面对于233魔方的尝试,输出结果几乎全都是0和1,所以我们尝试只用0和1两种操作。
int main()
{
CubeBlock block1(0, 8);//8角块
CubeBlock block2(1, 8);//8棱块
vectorb = vector{ block1,block2 };
vector>v1 = { {3,0,1,2,4,5,6,7},{3,0,1,2,4,5,6,7} };
vector>v2 = { {0,6,5,3,4,2,1,7},{0,5,2,3,4,1,6,7} };
vector>v3 = { {0,1,7,6,4,5,3,2},{0,1,6,3,4,5,2,7} };
vector>v4 = { {7,1,2,4,3,5,6,0},{0,1,2,7,4,5,6,3} };
vector>v5 = { {5,4,2,3,1,0,6,7},{4,1,2,3,0,5,6,7} };
CubeOpt op1(b, v1);
CubeOpt op2(b, v2);
CubeOpt op3(b, v3);
CubeOpt op4(b, v4);
CubeOpt op5(b, v5);
vectoropts = {op1,op2};
Cube(b, opts).dfs(1, 1, 2);
return 0;
}
输出:
0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0
公式太长了,为了寻找最短路,我决定改成bfs
BFS需要GetSingleId类新增根据id获取数据的接口。
把GetSingleId类改成:
template
class GetSingleId
{
public:
int id(T x)
{
auto it = m.find(Node{ &x });
if (it != m.end())return it->second;
v.push_back(x);
m[Node{ v.data() + v.size() - 1 }] = n;
return n++;
}
int num()
{
return n;
}
T* getData(int id)
{
return v.data() + id;
}
private:
struct Node {
T* x;
bool operator<(const Node& nod)const
{
return *x < *nod.x;
}
};
vectorv;
mapm;
int n = 0;
};
不知道为什么会报错。
于是我先用一个低效版代替:
template
class GetSingleId
{
public:
int id(T x)
{
auto it = m.find(x);
if (it != m.end())return it->second;
return m[x] = n++;
}
int num()
{
return n;
}
T getData(int id)
{
for (auto& mi : m)if (mi.second == id)return mi.first;
return T{};
}
private:
mapm;
int n = 0;
};
template
class GetCombineId
{
public:
vector combineId(vector& x)
{
if (v.empty())v.resize(x.size());
vectorans(x.size());
for (int i = 0; i < x.size(); i++)ans[i] = v[i].id(x[i]);
return ans;
}
int id(vector& x)
{
return v2.id(combineId(x));
}
int num()
{
return v2.num();
}
vector getData(int id)
{
vectorids = v2.getData(id);
vectorans(v.size());
for (int i = 0; i < v.size(); i++)ans[i] = v[i].getData(ids[i]);
return ans;
}
private:
vector>v;
GetSingleId>v2;
};
struct CubeBlock
{
int typeId;//角块,棱块等,分组id
vectorv;//一组块
CubeBlock() {}
CubeBlock(int id, int n)
{
typeId = id;
v.resize(n);
for (int i = 0; i < n; i++)v[i] = i;//每一组的块都按从0开始编号
}
int changeNum()
{
int ans = 0;
for (int i = 0; i < v.size(); i++)if (v[i] != i)ans++;
return ans;
}
bool isOk()
{
return changeNum() == 0;
}
bool operator<(const CubeBlock& blocks)const
{
for (int i = 0; i < v.size() && i < blocks.v.size(); i++) {
if (v[i] < blocks.v[i])return true;
if (blocks.v[i] < v[i])return false;
}
return false;
}
};
class CubeOpt
{
public:
CubeOpt(vector& b, vector>& v) :b{ b }, v{ v }{}//若干组块及其变换
CubeOpt& operator =(const CubeOpt& opt) {
b = opt.b, v = opt.v;
return *this;
}
void change()
{
for (int i = 0; i < v.size(); i++) {
change(b[i], v[i]);
}
}
void reback()
{
for (int i = 0; i < v.size(); i++) {
reback(b[i], v[i]);
}
}
private:
void change(CubeBlock& b, vector& v)//一组块及一个变换,如v[1]=2表示把2号块移到1号块的位置
{
vectorbv = b.v;
for (int i = 0; i < v.size(); i++) {
b.v[i] = bv[v[i]];
}
}
void reback(CubeBlock& b, vector& v)
{
vectorbv = b.v;
for (int i = 0; i < v.size(); i++) {
b.v[v[i]] = bv[i];
}
}
vector>& v;
vector& b;
};
class Cube
{
public:
Cube(vector& b, vector& opts) :b{ b }, opts{ opts }{}
int bfs(int targetId, int difNumLow, int difNumHigh)//推导出一个公式
{
queue>q;
q.push(b);
while (!q.empty()) {
b = q.front();
q.pop();
if (ok(b, targetId, difNumLow, difNumHigh)) {
return m.id(b);
}
int id = m.id(b);
for (int i = 0; i < opts.size(); i++) {
auto& opt = opts[i];
opt.change();
if (m.id(b) == m.num() - 1)q.push(b), fa[m.id(b)] = id;
opt.reback();
}
}
return 0;
}
vector> getAns(int id)
{
vector>v;
while(id) {
v.insert(v.begin(), m.getData(id));
id = fa[id];
}
v.insert(v.begin(), m.getData(id));
return v;
}
private:
bool ok(vector& b, int targetId, int difNumLow, int difNumHigh)
{
for (int i = 0; i < b.size(); i++) {
int c = b[i].changeNum();
if (i != targetId) {
if (c)return false;
}
else {
if (c < difNumLow || c > difNumHigh)return false;
}
}
return true;
}
vector&b;
vector&opts;
GetCombineIdm;
mapfa;
};
还是以金字塔二重奏魔方为例:
int main()
{
CubeBlock block1(0, 4);//4角块
CubeBlock block2(1, 4);//4棱块
vectorb = vector{ block1,block2 };
vector>v1 = { {0,1,2,3},{1,2,0,3} };
vector>v2 = { {0,1,2,3},{3,0,2,1} };
vector>v3 = { {0,1,2,3},{0,3,1,2} };
vector>v4 = { {0,1,2,3},{2,1,3,0} };
CubeOpt op1(b, v1);
CubeOpt op2(b, v2);
CubeOpt op3(b, v3);
CubeOpt op4(b, v4);
vectoropts = { op1,op2,op3,op4 };
Cube cube(b, opts);
int ansId = cube.bfs(1, 4, 4);
vector> v = cube.getAns(ansId);
for (int i = 1; i < v.size(); i++) {
for (int j = 0; j < opts.size(); j++) {
auto v1 = v[i - 1], v2 = v[i];
b = v1;
opts[j].change();
bool same = true;
for (int k = 0; k < v2.size(); k++)if (v2[k] < b[k] || b[k] < v2[k])same = false;
if (same) {
cout << j << " ";
break;
}
}
}
return 0;
}
输出0 0 1(这个顺序是正着的)
再用四轴旋转魔方试一下:
int main()
{
CubeBlock block1(0, 8);//8角块
CubeBlock block2(1, 6);//6棱块
vectorb = vector{ block1,block2 };
vector>v1 = { {0,3,2,6,4,5,1,7},{2,1,5,3,4,0} };
vector>v2 = { {2,1,5,3,4,0,6,7},{5,1,2,0,4,3} };
vector>v3 = { {0,4,2,1,3,5,6,7},{3,1,2,4,0,5} };
vector>v4 = { {7,1,0,3,4,5,6,2},{4,1,0,3,2,5} };
CubeOpt op1(b, v1);
CubeOpt op2(b, v2);
CubeOpt op3(b, v3);
CubeOpt op4(b, v4);
vectoropts = { op1,op2,op3,op4 };
Cube cube(b, opts);
int ansId = cube.bfs(1, 1, 6);
vector> v = cube.getAns(ansId);
for (int i = 1; i < v.size(); i++) {
for (int j = 0; j < opts.size(); j++) {
auto v1 = v[i - 1], v2 = v[i];
b = v1;
opts[j].change();
bool same = true;
for (int k = 0; k < v2.size(); k++)if (v2[k] < b[k] || b[k] < v2[k])same = false;
if (same) {
cout << j << " ";
break;
}
if (j == opts.size() - 1)cout << "? ";
}
}
return 0;
}
输出:0 0 1 0 1 1
再拿233魔方试一下:
int main()
{
CubeBlock block1(0, 8);//8角块
CubeBlock block2(1, 8);//8棱块
vectorb = vector{ block1,block2 };
vector>v1 = { {3,0,1,2,4,5,6,7},{3,0,1,2,4,5,6,7} };
vector>v2 = { {0,6,5,3,4,2,1,7},{0,5,2,3,4,1,6,7} };
vector>v3 = { {0,1,7,6,4,5,3,2},{0,1,6,3,4,5,2,7} };
vector>v4 = { {7,1,2,4,3,5,6,0},{0,1,2,7,4,5,6,3} };
vector>v5 = { {5,4,2,3,1,0,6,7},{4,1,2,3,0,5,6,7} };
CubeOpt op1(b, v1);
CubeOpt op2(b, v2);
CubeOpt op3(b, v3);
CubeOpt op4(b, v4);
CubeOpt op5(b, v5);
vectoropts = { op1,op2,op3,op4,op5 };
Cube cube(b, opts);
int ansId = cube.bfs(1, 1, 3);
vector> v = cube.getAns(ansId);
for (int i = 1; i < v.size(); i++) {
for (int j = 0; j < opts.size(); j++) {
auto v1 = v[i - 1], v2 = v[i];
b = v1;
opts[j].change();
bool same = true;
for (int k = 0; k < v2.size(); k++)if (v2[k] < b[k] || b[k] < v2[k])same = false;
if (same) {
cout << j << " ";
break;
}
if (j == opts.size() - 1)cout << "? ";
}
}
return 0;
}
输出:0 0 1 0 0 1 0 0 1
这个公式的效果是交换顶层不相邻的2个棱块。
计算cube.bfs(1, 3, 3),输出:0 0 1 2 1 0 0 1 2 1
改成:
class Cube
{
public:
Cube(vector& b, vector& opts) :b{ b }, opts{ opts }{}
int bfs(int targetId, int difNumLow, int difNumHigh)//推导出一个公式
{
queue>q;
q.push(b);
while (!q.empty()) {
b = q.front();
q.pop();
if (ok(b, targetId, difNumLow, difNumHigh)) {
showAns(m.id(b));
}
int id = m.id(b);
for (int i = 0; i < opts.size(); i++) {
auto& opt = opts[i];
opt.change();
if (m.id(b) == m.num() - 1)q.push(b), fa[m.id(b)] = id;
opt.reback();
}
}
return 0;
}
vector> getAns(int id)
{
vector>v;
while(id) {
v.insert(v.begin(), m.getData(id));
id = fa[id];
}
v.insert(v.begin(), m.getData(id));
return v;
}
void showAns(int ansId)
{
vector> v = getAns(ansId);
for (int i = 1; i < v.size(); i++) {
for (int j = 0; j < opts.size(); j++) {
auto v1 = v[i - 1], v2 = v[i];
b = v1;
opts[j].change();
bool same = true;
for (int k = 0; k < v2.size(); k++)if (v2[k] < b[k] || b[k] < v2[k])same = false;
if (same) {
cout << j << " ";
break;
}
if (j == opts.size() - 1)cout << "? ";
}
}
cout << endl;
}
private:
bool ok(vector& b, int targetId, int difNumLow, int difNumHigh)
{
for (int i = 0; i < b.size(); i++) {
int c = b[i].changeNum();
if (i != targetId) {
if (c)return false;
}
else {
if (c < difNumLow || c > difNumHigh)return false;
}
}
return true;
}
vector&b;
vector&opts;
GetCombineIdm;
mapfa;
};
int main()
{
CubeBlock block1(0, 8);//8角块
CubeBlock block2(1, 8);//8棱块
vectorb = vector{ block1,block2 };
vector>v1 = { {3,0,1,2,4,5,6,7},{3,0,1,2,4,5,6,7} };
vector>v2 = { {0,6,5,3,4,2,1,7},{0,5,2,3,4,1,6,7} };
vector>v3 = { {0,1,7,6,4,5,3,2},{0,1,6,3,4,5,2,7} };
vector>v4 = { {7,1,2,4,3,5,6,0},{0,1,2,7,4,5,6,3} };
vector>v5 = { {5,4,2,3,1,0,6,7},{4,1,2,3,0,5,6,7} };
CubeOpt op1(b, v1);
CubeOpt op2(b, v2);
CubeOpt op3(b, v3);
CubeOpt op4(b, v4);
CubeOpt op5(b, v5);
vectoropts = { op1,op2,op3,op4,op5 };
Cube cube(b, opts);
cube.bfs(1, 2, 2);
return 0;
}