目录
[刷新方案(V1 -> V2)](#刷新方案(V1 -> V2))
七彩鹦鹉螺魔方
魔方三要素
(1)组成部件
一共3层,每层7个不同的部件,按照从小到大分别是粉色,紫色,蓝色,绿色,黄色,橙色,红色。
(2)可执行操作
一共三种操作:旋转顶层、旋转底层、对半翻转。
为了方便,我们提出一个大操作的概念,即若干次旋转顶层+若干次旋转底层+1次对半翻转+若干次旋转顶层+若干次旋转底层,其中的若干可以为0。
显然,魔方的打乱和复原都是一系列的大操作。
(3)目标态
恢复鹦鹉螺的外形,即每个部件回到原本的位置。
根据对半翻转做角度推理
假设粉色,紫色,蓝色,绿色,黄色,橙色,红色分别是x1 x2 x3 x4 x5 x6 x7度,则x1+x2+x3+x4+x5+x6+x7=360
根据能完成对半翻转的场景,提出新的等式。
场景1:

则x1+x6+x7=180,x2+x3+x4+x5=180
场景2:

x1+x2+x3+x7=180,x4+x5+x6=180
场景3:

x7+x7=180
根据这3个场景,目前得到的方程组是:
x1=90-x6
x2+x3=x6
x4+x5=180-x6
x7=90
所以,还需要寻找3个条件。
场景4:

新增条件x3+x4=90
方程组变成:
x1=90-x6
x2=x6-x3
x4=90-x3
x5=90-x2
x7=90
所以,还需要寻找2个条件。
根据组合做角度推理
根据已有的5个方程:
x1=90-x6
x2=x6-x3
x4=90-x3
x5=90-x2
x7=90
我们先做出一个推测 x1到x7分别是20 30 40 50 60 70 90
那么,在其中选若干个数加起来能构成180的情况只有9种:
90+90=180
20+70+90=180
30+60+90=180
40+50+90=180
20+30+40+90=180
50+60+70=180
20+30+60+70=180
20+40+50+70=180
30+40+50+60=180
把这个转换成方程组就是:
x7+x7=180
x1+x6+x7=180
x2+x5+x7=180
x3+x4+x7=180
x1+x2+x3+x7=180
x4+x5+x6=180
x1+x2+x5+x6=180
x1+x3+x4+x6=180
x2+x3+x4+x5=180
不难发现,上述5个方程构成的不定方程组的任意解都是满足这9个方程的。
所以,无论具体角度是多少,只需要满足这5个方程,得到的七彩鹦鹉螺魔方一定是等价的。
既然如此,那么我们不妨设角度就是20 30 40 50 60 70 90
PS:生产厂家为了方便,大概率取的也就是这7个值
有趣的形态



所有形态枚举(V1)
中间层固定把红色(90度)放左上角,粉色紫色蓝色(20 30 40度)放左下角,那么竖直的线就是分割线。
按照时钟的顺序,顶层的初始状态是70 60 50 40 30 20 90,底层的初始状态是50 60 70 90 20 30 40
中间层的初始状态是0,唯一的非初始状态是1
cpp
//通用的数据缓存去重编号方案
template<typename T>
class GetSingleId
{
public:
int id(T x) //所有元素按照首次传入顺序编号0,1,2......
{
auto it = m.find(x);
if (it != m.end())return it->second;
mr[n] = x;
return m[x] = n++;
}
int num() //id()==num()-1表示是新元素,否则是重复元素
{
return n;
}
T getData(int id) //根据id获取元素数据
{
return mr[id];
}
private:
map<T, int>m;
map<int, T>mr;
int n = 0;
};
struct Node {
vector<int>up{ 70,60,50,40,30,20,90 };
int mid = 0;
vector<int>down{ 50,60,70,90,20,30,40 };
int ans = 0;
};
int getId(vector<int> v) {
static GetSingleId<vector<int>> opt;
int ans = opt.id(v);
int len = v.size();
while (len--) {
v.push_back(v[0]);
v.erase(v.begin());
opt.id(v);
}
return ans;
}
int getId(const Node &nod)
{
static GetSingleId<vector<int>> opt;
int id1 = getId(nod.up);
int id2 = getId(nod.down);
return opt.id(vector<int>{id1, nod.mid, id2});
}
vector<int> findId(const vector<int>&v)
{
vector<int>ans;
for (int i = 0; i < v.size(); i++) {
int s = 0;
for (int j = i; j < i + v.size(); j++) {
s += v[j%v.size()];
if (s >= 180)break;
}
if (s == 180)ans.push_back(i);
}
return ans;
}
vector<Node> getNext(const Node &nod)
{
vector<int> id1 = findId(nod.up);
vector<int> id2 = findId(nod.down);
vector<Node> ans;
for (int i : id1) {
for (int j : id2) {
vector<int>v1, v2;
int k1 = i, k2 = j, s1 = 0, s2 = 0;
while (s1 < 180) {
v1.push_back(nod.down[k2]);
s1 += nod.down[k2];
k2 = (k2 + 1) % nod.down.size();
}
while (s2 < 180) {
v2.push_back(nod.up[k1]);
s2 += nod.up[k1];
k1 = (k1 + 1) % nod.up.size();
}
while (k1 != i) {
v1.push_back(nod.up[k1]);
k1 = (k1 + 1) % nod.up.size();
}
while (k2 != j) {
v2.push_back(nod.down[k2]);
k2 = (k2 + 1) % nod.down.size();
}
ans.push_back({ v1,1 - nod.mid,v2,nod.ans + 1 });
}
}
return ans;
}
//假设对半翻转操作是长度为1,另外2个操作是长度为0,对整个图进行bfs搜出单源最短路径
void bfs()
{
Node nod;
set<int>s;
s.insert(getId(nod));
queue<Node>q;
q.push(nod);
int num = 0;
while (!q.empty()) {
auto nod = q.front();
num++;
for (int x : nod.up)cout << x << " ";
cout << endl << nod.mid << endl;
for (int x : nod.down)cout << x << " ";
cout << endl << nod.ans<<endl << endl;
q.pop();
auto v = getNext(nod);
for (auto nod : v) {
int id = getId(nod);
if (s.find(id) == s.end()) {
s.insert(id);
q.push(nod);
}
}
}
cout << num;
}
int main() {
bfs();
return 0;
}
输出:
......
30 60 30 60 40 90 50
0
90 70 20 20 50 40 70
14
20 50 40 70 40 90 50
0
90 70 20 30 60 30 60
14
4032
一共4032种不同的形态,其中任意2个形态之间的转换至少需要1次大操作。
也就是说,只旋转顶层、旋转底层得到的状态已经合并了,合并后的总数是4032=63*64
显然,这个数字通过组合的方法去推也是能推出来的,当然前提是对于可达状态集有了判定方法。
最速复原跳转表(V1)
前面的输出结果已经表明,最多需要14次大操作才能复原。
这里给出具体的操作路径:
cpp
//通用的数据缓存去重编号方案
template<typename T>
class GetSingleId
{
public:
int id(T x) //所有元素按照首次传入顺序编号0,1,2......
{
auto it = m.find(x);
if (it != m.end())return it->second;
mr[n] = x;
return m[x] = n++;
}
int num() //id()==num()-1表示是新元素,否则是重复元素
{
return n;
}
T getData(int id) //根据id获取元素数据
{
return mr[id];
}
private:
map<T, int>m;
map<int, T>mr;
int n = 0;
};
struct Node {
vector<int>up{ 70,60,50,40,30,20,90 };
int mid = 0;
vector<int>down{ 50,60,70,90,20,30,40 };
int ans = 0;
int id = 0;
int fa = 0;
};
int getId(vector<int> v) {
static GetSingleId<vector<int>> opt;
int ans = opt.id(v);
int len = v.size();
while (len--) {
v.push_back(v[0]);
v.erase(v.begin());
opt.id(v);
}
return ans;
}
int getId(const Node &nod)
{
static GetSingleId<vector<int>> opt;
int id1 = getId(nod.up);
int id2 = getId(nod.down);
return opt.id(vector<int>{id1, nod.mid, id2});
}
vector<int> findId(const vector<int>&v)
{
vector<int>ans;
for (int i = 0; i < v.size(); i++) {
int s = 0;
for (int j = i; j < i + v.size(); j++) {
s += v[j%v.size()];
if (s >= 180)break;
}
if (s == 180)ans.push_back(i);
}
return ans;
}
vector<Node> getNext(const Node &nod)
{
vector<int> id1 = findId(nod.up);
vector<int> id2 = findId(nod.down);
vector<Node> ans;
for (int i : id1) {
for (int j : id2) {
vector<int>v1, v2;
int k1 = i, k2 = j, s1 = 0, s2 = 0;
while (s1 < 180) {
v1.push_back(nod.down[k2]);
s1 += nod.down[k2];
k2 = (k2 + 1) % nod.down.size();
}
while (s2 < 180) {
v2.push_back(nod.up[k1]);
s2 += nod.up[k1];
k1 = (k1 + 1) % nod.up.size();
}
while (k1 != i) {
v1.push_back(nod.up[k1]);
k1 = (k1 + 1) % nod.up.size();
}
while (k2 != j) {
v2.push_back(nod.down[k2]);
k2 = (k2 + 1) % nod.down.size();
}
ans.push_back({ v1,1 - nod.mid,v2,nod.ans + 1,0,0 });
}
}
return ans;
}
//假设对半翻转操作是长度为1,另外2个操作是长度为0,对整个图进行bfs搜出单源最短路径
void bfs()
{
Node nod;
set<int>s;
s.insert(getId(nod));
queue<Node>q;
q.push(nod);
while (!q.empty()) {
auto nod = q.front();
int fa = nod.id;
cout << "序号="<<nod.id << " ";
for (int x : nod.up)cout << x << " ";
cout << " " << nod.mid << " ";
for (int x : nod.down)cout << x << " ";
cout << " 跳转到序号" << nod.fa << endl;
q.pop();
auto v = getNext(nod);
for (auto nod : v) {
int id = getId(nod);
if (s.find(id) == s.end()) {
s.insert(id);
nod.id = id;
nod.fa = fa;
q.push(nod);
}
}
}
}
int main() {
bfs();
return 0;
}
输出结果:
cpp
序号=0 70 60 50 40 30 20 90 0 50 60 70 90 20 30 40 跳转到序号0
序号=1 50 60 70 40 30 20 90 1 70 60 50 90 20 30 40 跳转到序号0
序号=2 70 90 20 40 30 20 90 1 70 60 50 30 40 50 60 跳转到序号0
序号=3 90 20 30 40 40 30 20 90 1 70 60 50 50 60 70 跳转到序号0
序号=4 30 40 50 60 40 30 20 90 1 70 60 50 70 90 20 跳转到序号0
序号=5 50 60 70 20 90 70 1 60 50 40 30 90 20 30 40 跳转到序号0
序号=6 70 90 20 20 90 70 1 60 50 40 30 30 40 50 60 跳转到序号0
序号=7 90 20 30 40 20 90 70 1 60 50 40 30 50 60 70 跳转到序号0
。。。。。。
序号=4021 20 50 40 70 30 60 30 60 0 40 90 50 90 70 20 跳转到序号3887
序号=4022 90 70 20 40 90 50 0 30 60 30 60 20 50 40 70 跳转到序号3887
序号=4023 20 50 40 70 40 90 50 0 30 60 30 60 90 70 20 跳转到序号3887
序号=4024 30 60 30 60 90 70 20 0 20 50 40 70 40 90 50 跳转到序号3890
序号=4025 40 90 50 90 70 20 0 20 50 40 70 30 60 30 60 跳转到序号3890
序号=4026 30 60 30 60 20 50 40 70 0 90 70 20 40 90 50 跳转到序号3890
序号=4027 40 90 50 20 50 40 70 0 90 70 20 30 60 30 60 跳转到序号3890
序号=4028 30 60 30 60 90 70 20 0 40 90 50 20 50 40 70 跳转到序号3891
序号=4029 20 50 40 70 90 70 20 0 40 90 50 30 60 30 60 跳转到序号3891
序号=4030 30 60 30 60 40 90 50 0 90 70 20 20 50 40 70 跳转到序号3891
序号=4031 20 50 40 70 40 90 50 0 90 70 20 30 60 30 60 跳转到序号3891
篇幅太长无法发表,省略。
使用示例:


那么这就是 90 90 40 40 50 30 20 0 70 60 20 30 60 70 50 (需要适当的旋转才能在这4032个情况中找到唯一对应的那个)
对应的答案就是:
序号=2102 90 90 40 40 50 30 20 0 70 60 20 30 60 70 50 跳转到序号1495
序号=1495 20 30 40 40 50 30 20 70 60 1 90 90 60 70 50 跳转到序号753
序号=753 30 20 70 60 90 90 0 50 60 70 50 20 30 40 40 跳转到序号186
序号=186 50 60 70 90 90 1 20 30 40 40 30 20 70 60 50 跳转到序号17
序号=17 90 20 30 40 40 30 20 90 0 50 60 70 70 60 50 跳转到序号1
序号=1 50 60 70 40 30 20 90 1 70 60 50 90 20 30 40 跳转到序号0
启发式策略(单节点)(V1)
首先我们想到的策略自然是合并。
然后基于上面代码输出的4032个具体状态,我很快锁定了50+60这个组合。
(一开始我想的是类似于20+30+40或者40+50这种组合,但是并没有明确的发现)
用代码来验证一下:
cpp
//通用的数据缓存去重编号方案
template<typename T>
class GetSingleId
{
public:
int id(T x) //所有元素按照首次传入顺序编号0,1,2......
{
auto it = m.find(x);
if (it != m.end())return it->second;
mr[n] = x;
return m[x] = n++;
}
int num() //id()==num()-1表示是新元素,否则是重复元素
{
return n;
}
T getData(int id) //根据id获取元素数据
{
return mr[id];
}
private:
map<T, int>m;
map<int, T>mr;
int n = 0;
};
struct Node {
vector<int>up{ 70,60,50,40,30,20,90 };
int mid = 0;
vector<int>down{ 50,60,70,90,20,30,40 };
int ans = 0;
int id = 0;
int fa = 0;
};
int getId(vector<int> v) {
static GetSingleId<vector<int>> opt;
int ans = opt.id(v);
int len = v.size();
while (len--) {
v.push_back(v[0]);
v.erase(v.begin());
opt.id(v);
}
return ans;
}
int getId(const Node& nod)
{
static GetSingleId<vector<int>> opt;
int id1 = getId(nod.up);
int id2 = getId(nod.down);
return opt.id(vector<int>{id1, nod.mid, id2});
}
vector<int> findId(const vector<int>& v)
{
vector<int>ans;
for (int i = 0; i < v.size(); i++) {
int s = 0;
for (int j = i; j < i + v.size(); j++) {
s += v[j % v.size()];
if (s >= 180)break;
}
if (s == 180)ans.push_back(i);
}
return ans;
}
vector<Node> getNext(const Node& nod)
{
vector<int> id1 = findId(nod.up);
vector<int> id2 = findId(nod.down);
vector<Node> ans;
for (int i : id1) {
for (int j : id2) {
vector<int>v1, v2;
int k1 = i, k2 = j, s1 = 0, s2 = 0;
while (s1 < 180) {
v1.push_back(nod.down[k2]);
s1 += nod.down[k2];
k2 = (k2 + 1) % nod.down.size();
}
while (s2 < 180) {
v2.push_back(nod.up[k1]);
s2 += nod.up[k1];
k1 = (k1 + 1) % nod.up.size();
}
while (k1 != i) {
v1.push_back(nod.up[k1]);
k1 = (k1 + 1) % nod.up.size();
}
while (k2 != j) {
v2.push_back(nod.down[k2]);
k2 = (k2 + 1) % nod.down.size();
}
ans.push_back({ v1,1 - nod.mid,v2,nod.ans + 1,0,0 });
}
}
return ans;
}
//假设对半翻转操作是长度为1,另外2个操作是长度为0,对整个图进行bfs搜出单源最短路径
vector<int> bfs(vector<Node>&vn)
{
vector<int> ans(4032);
Node nod;
set<int>s;
s.insert(getId(nod));
queue<Node>q;
q.push(nod);
while (!q.empty()) {
auto nod = q.front();
int fa = nod.id;
int newAns = nod.ans + 1;
ans[fa] = nod.fa;
vn.push_back(nod);
q.pop();
auto v = getNext(nod);
for (auto nod : v) {
int id = getId(nod);
if (s.find(id) == s.end()) {
s.insert(id);
nod.id = id;
nod.fa = fa;
nod.ans = newAns;
q.push(nod);
}
}
}
return ans;
}
bool check56(const vector<int>& v)
{
int s50 = 0, s60 = 0;
for (auto x : v) {
if (x == 50)s50++;
if (x == 60)s60++;
}
if (s50 != s60)return false;
for (int i = 0; i < v.size(); i++) {
if (v[i] != 50 && v[i] != 60)continue;
if (v[(i + 1) % v.size()] != 110 - v[i] && v[(i + v.size() - 1) % v.size()] != 110 - v[i])return false;
}
return true;
}
bool check56(const Node& nod)
{
return check56(nod.up) && check56(nod.down);
}
int getLen(vector<Node>& vn, vector<int>& fa, int id)
{
int s = 0;
while (!check56(vn[id])) {
s++;
id = fa[id];
}
return s;
}
int main() {
vector<Node> vn;
vector<int> fa = bfs(vn);
for (int i = 0; i < fa.size(); i++) {
cout << i << " " << fa[i] << endl;
}
int max1 = 0, max2 = 0, maxs = 0;
for (int i = 0; i < fa.size(); i++) {
int x = getLen(vn, fa, i);
max1 = max(max1, x);
max2 = max(max2, vn[i].ans - x);
maxs = max(maxs, vn[i].ans);
}
cout << endl << "max:" << max1 << " " << max2 << " " << maxs;
return 0;
}
输出:
。。。。。。
4025 3890
4026 3890
4027 3890
4028 3891
4029 3891
4030 3891
4031 3891
max:11 7 14
所以我们得到结论:所有状态的最速复原都可以分为2步,第一步是完成2组50+60的合并,第二步是彻底复原。其中的第一步,最多需要11次大操作,其中的第二步,最多需要7次大操作,而总共最多需要14次大操作。
实际上,不管选什么状态作为跳转节点,只要终点是满足状态的,我们都可以说,最速复原都可以分为2步,第一步是***,第二步是***,第一步最多需要x次大操作,第二步最多需要y次大操作,而总共最多需要14次操作。
其中,x和y都是不超过14的。x和y越大,则这个启发式策略越不具备启发性,如果x或y等于14,则完全不具备启发性。
启发式策略(双节点)(V1)
我们对上面的策略做一个细化、强化
cpp
//通用的数据缓存去重编号方案
template<typename T>
class GetSingleId
{
public:
int id(T x) //所有元素按照首次传入顺序编号0,1,2......
{
auto it = m.find(x);
if (it != m.end())return it->second;
mr[n] = x;
return m[x] = n++;
}
int num() //id()==num()-1表示是新元素,否则是重复元素
{
return n;
}
T getData(int id) //根据id获取元素数据
{
return mr[id];
}
private:
map<T, int>m;
map<int, T>mr;
int n = 0;
};
struct Node {
vector<int>up{ 70,60,50,40,30,20,90 };
int mid = 0;
vector<int>down{ 50,60,70,90,20,30,40 };
int ans = 0;
int id = 0;
int fa = 0;
};
int getId(vector<int> v) {
static GetSingleId<vector<int>> opt;
int ans = opt.id(v);
int len = v.size();
while (len--) {
v.push_back(v[0]);
v.erase(v.begin());
opt.id(v);
}
return ans;
}
int getId(const Node& nod)
{
static GetSingleId<vector<int>> opt;
int id1 = getId(nod.up);
int id2 = getId(nod.down);
return opt.id(vector<int>{id1, nod.mid, id2});
}
vector<int> findId(const vector<int>& v)
{
vector<int>ans;
for (int i = 0; i < v.size(); i++) {
int s = 0;
for (int j = i; j < i + v.size(); j++) {
s += v[j % v.size()];
if (s >= 180)break;
}
if (s == 180)ans.push_back(i);
}
return ans;
}
vector<Node> getNext(const Node& nod)
{
vector<int> id1 = findId(nod.up);
vector<int> id2 = findId(nod.down);
vector<Node> ans;
for (int i : id1) {
for (int j : id2) {
vector<int>v1, v2;
int k1 = i, k2 = j, s1 = 0, s2 = 0;
while (s1 < 180) {
v1.push_back(nod.down[k2]);
s1 += nod.down[k2];
k2 = (k2 + 1) % nod.down.size();
}
while (s2 < 180) {
v2.push_back(nod.up[k1]);
s2 += nod.up[k1];
k1 = (k1 + 1) % nod.up.size();
}
while (k1 != i) {
v1.push_back(nod.up[k1]);
k1 = (k1 + 1) % nod.up.size();
}
while (k2 != j) {
v2.push_back(nod.down[k2]);
k2 = (k2 + 1) % nod.down.size();
}
ans.push_back({ v1,1 - nod.mid,v2,nod.ans + 1,0,0 });
}
}
return ans;
}
//假设对半翻转操作是长度为1,另外2个操作是长度为0,对整个图进行bfs搜出单源最短路径
vector<int> bfs(vector<Node>&vn)
{
vector<int> ans(4032);
Node nod;
set<int>s;
s.insert(getId(nod));
queue<Node>q;
q.push(nod);
while (!q.empty()) {
auto nod = q.front();
int fa = nod.id;
int newAns = nod.ans + 1;
ans[fa] = nod.fa;
vn.push_back(nod);
q.pop();
auto v = getNext(nod);
for (auto nod : v) {
int id = getId(nod);
if (s.find(id) == s.end()) {
s.insert(id);
nod.id = id;
nod.fa = fa;
nod.ans = newAns;
q.push(nod);
}
}
}
return ans;
}
bool check5656(const vector<int>& v)
{
int s50 = 0, s60 = 0;
for (auto x : v) {
if (x == 50)s50++;
if (x == 60)s60++;
}
if (s50 != s60)return false;
for (int i = 0; i < v.size(); i++) {
if (v[i] != 50 && v[i] != 60)continue;
if (v[(i + 1) % v.size()] != 110 - v[i] && v[(i + v.size() - 1) % v.size()] != 110 - v[i])return false;
}
return true;
}
bool check5656(const Node& nod)
{
return check5656(nod.up) && check5656(nod.down);
}
bool check56(const vector<int>& v)
{
for (int i = 0; i < v.size(); i++) {
if (v[i] != 50 && v[i] != 60)continue;
if (v[(i + 1) % v.size()] == 110 - v[i])return true;
}
return false;
}
bool check56(const Node& nod)
{
return check56(nod.up) || check56(nod.down);
}
void getLen(vector<Node>& vn, vector<int>& fa, int id,int &len1,int &len2)
{
int id0 = id;
len1 = 0, len2 = 0;
while (!check56(vn[id])) {
len1++;
id = fa[id];
}
while (!check5656(vn[id])) {
len2++;
id = fa[id];
}
cout << id0<<" "<< len1 << " " << len2 << " " << vn[id0].ans - len1 - len2 << endl;
}
int main() {
vector<Node> vn;
vector<int> fa = bfs(vn);
for (int i = 0; i < fa.size(); i++) {
cout << i << " " << fa[i] << endl;
}
int max1 = 0, max2 = 0, max3=0,maxs = 0;
for (int i = 0; i < fa.size(); i++) {
int len1, len2;
getLen(vn, fa, i, len1, len2);
max1 = max(max1, len1);
max2 = max(max2, len2);
max3 = max(max3, vn[i].ans - len1 - len2);
maxs = max(maxs, vn[i].ans);
}
cout << endl << "max:" << max1 << " " << max2 << " "<< max3<<" " << maxs;
return 0;
}
输出:
。。。。。。
4012 1 10 3
4013 1 10 3
4014 1 10 3
4015 1 10 3
4016 8 3 3
4017 8 3 3
4018 8 3 3
4019 8 3 3
4020 8 3 3
4021 8 3 3
4022 8 3 3
4023 8 3 3
4024 8 3 3
4025 8 3 3
4026 8 3 3
4027 8 3 3
4028 8 3 3
4029 8 3 3
4030 8 3 3
4031 8 3 3
max:8 11 7 14
结果并不理想,数字还是比较大。
但是不难发现,只有极少数是形如1 10 3这样的极端数据,大部分都是8 3 3 这样比较好的数据。
对这些少部分数据进行进一步分析,也没有明显的发现。
此时,我猜想这个双节点策略可能是有效的,问题可能出在由fa组成的树,这棵树蕴含的只是其中一种最优解,不包含所有最优解的信息。
所以,我们需要重新做BFS。
重新编码时,发现对状态进行去重编号的方案有问题,以下是刷新结果。
刷新方案(V1 -> V2)
只需要更新这一个函数(另外4032这个魔鬼数字也需要改掉)
cpp
int getId(vector<int> v) {
static map< vector<int>, int>m;
if (m.find(v) != m.end())return m[v];
int ans = m.size();
int len = v.size();
while (len--) {
v.push_back(v[0]);
v.erase(v.begin());
m[v] = ans;
}
return ans;
}
所有形态枚举(V2)
cpp
//通用的数据缓存去重编号方案
template<typename T>
class GetSingleId
{
public:
int id(T x) //所有元素按照首次传入顺序编号0,1,2......
{
auto it = m.find(x);
if (it != m.end())return it->second;
mr[n] = x;
return m[x] = n++;
}
int num() //id()==num()-1表示是新元素,否则是重复元素
{
return n;
}
T getData(int id) //根据id获取元素数据
{
return mr[id];
}
private:
map<T, int>m;
map<int, T>mr;
int n = 0;
};
struct Node {
vector<int>up{ 70,60,50,40,30,20,90 };
int mid = 0;
vector<int>down{ 50,60,70,90,20,30,40 };
int ans = 0;
};
int getId(vector<int> v) {
static map< vector<int>, int>m;
if (m.find(v) != m.end())return m[v];
int ans = m.size();
int len = v.size();
while (len--) {
v.push_back(v[0]);
v.erase(v.begin());
m[v] = ans;
}
return ans;
}
int getId(const Node &nod)
{
static GetSingleId<vector<int>> opt;
int id1 = getId(nod.up);
int id2 = getId(nod.down);
return opt.id(vector<int>{id1, nod.mid, id2});
}
vector<int> findId(const vector<int>&v)
{
vector<int>ans;
for (int i = 0; i < v.size(); i++) {
int s = 0;
for (int j = i; j < i + v.size(); j++) {
s += v[j%v.size()];
if (s >= 180)break;
}
if (s == 180)ans.push_back(i);
}
return ans;
}
vector<Node> getNext(const Node &nod)
{
vector<int> id1 = findId(nod.up);
vector<int> id2 = findId(nod.down);
vector<Node> ans;
for (int i : id1) {
for (int j : id2) {
vector<int>v1, v2;
int k1 = i, k2 = j, s1 = 0, s2 = 0;
while (s1 < 180) {
v1.push_back(nod.down[k2]);
s1 += nod.down[k2];
k2 = (k2 + 1) % nod.down.size();
}
while (s2 < 180) {
v2.push_back(nod.up[k1]);
s2 += nod.up[k1];
k1 = (k1 + 1) % nod.up.size();
}
while (k1 != i) {
v1.push_back(nod.up[k1]);
k1 = (k1 + 1) % nod.up.size();
}
while (k2 != j) {
v2.push_back(nod.down[k2]);
k2 = (k2 + 1) % nod.down.size();
}
ans.push_back({ v1,1 - nod.mid,v2,nod.ans + 1 });
}
}
return ans;
}
//假设对半翻转操作是长度为1,另外2个操作是长度为0,对整个图进行bfs搜出单源最短路径
void bfs()
{
Node nod;
set<int>s;
s.insert(getId(nod));
queue<Node>q;
q.push(nod);
int num = 0;
while (!q.empty()) {
auto nod = q.front();
num++;
for (int x : nod.up)cout << x << " ";
cout << endl << nod.mid << endl;
for (int x : nod.down)cout << x << " ";
cout << endl << nod.ans << endl << endl;
q.pop();
auto v = getNext(nod);
for (auto nod : v) {
int id = getId(nod);
if (s.find(id) == s.end()) {
s.insert(id);
q.push(nod);
}
}
}
cout << num;
}
int main() {
bfs();
return 0;
}
输出:
。。。。。。
40 90 50 30 60 30 60
1
90 70 20 20 50 40 70
13
20 50 40 70 90 70 20
1
30 60 30 60 40 90 50
13
40 90 50 90 70 20
1
30 60 30 60 20 50 40 70
13
652
一共652种不同的形态,其中任意2个形态之间的转换至少需要1次大操作。
最速复原跳转表(V2)
前面的输出结果已经表明,最多需要13次大操作才能复原。
这里给出具体的操作路径:
cpp
//通用的数据缓存去重编号方案
template<typename T>
class GetSingleId
{
public:
int id(T x) //所有元素按照首次传入顺序编号0,1,2......
{
auto it = m.find(x);
if (it != m.end())return it->second;
mr[n] = x;
return m[x] = n++;
}
int num() //id()==num()-1表示是新元素,否则是重复元素
{
return n;
}
T getData(int id) //根据id获取元素数据
{
return mr[id];
}
private:
map<T, int>m;
map<int, T>mr;
int n = 0;
};
struct Node {
vector<int>up{ 70,60,50,40,30,20,90 };
int mid = 0;
vector<int>down{ 50,60,70,90,20,30,40 };
int ans = 0;
int id = 0;
int fa = 0;
};
int getId(vector<int> v) {
static map< vector<int>, int>m;
if (m.find(v) != m.end())return m[v];
int ans = m.size();
int len = v.size();
while (len--) {
v.push_back(v[0]);
v.erase(v.begin());
m[v] = ans;
}
return ans;
}
int getId(const Node &nod)
{
static GetSingleId<vector<int>> opt;
int id1 = getId(nod.up);
int id2 = getId(nod.down);
return opt.id(vector<int>{id1, nod.mid, id2});
}
vector<int> findId(const vector<int>&v)
{
vector<int>ans;
for (int i = 0; i < v.size(); i++) {
int s = 0;
for (int j = i; j < i + v.size(); j++) {
s += v[j%v.size()];
if (s >= 180)break;
}
if (s == 180)ans.push_back(i);
}
return ans;
}
vector<Node> getNext(const Node &nod)
{
vector<int> id1 = findId(nod.up);
vector<int> id2 = findId(nod.down);
vector<Node> ans;
for (int i : id1) {
for (int j : id2) {
vector<int>v1, v2;
int k1 = i, k2 = j, s1 = 0, s2 = 0;
while (s1 < 180) {
v1.push_back(nod.down[k2]);
s1 += nod.down[k2];
k2 = (k2 + 1) % nod.down.size();
}
while (s2 < 180) {
v2.push_back(nod.up[k1]);
s2 += nod.up[k1];
k1 = (k1 + 1) % nod.up.size();
}
while (k1 != i) {
v1.push_back(nod.up[k1]);
k1 = (k1 + 1) % nod.up.size();
}
while (k2 != j) {
v2.push_back(nod.down[k2]);
k2 = (k2 + 1) % nod.down.size();
}
ans.push_back({ v1,1 - nod.mid,v2,nod.ans + 1,0,0 });
}
}
return ans;
}
//假设对半翻转操作是长度为1,另外2个操作是长度为0,对整个图进行bfs搜出单源最短路径
void bfs()
{
Node nod;
set<int>s;
s.insert(getId(nod));
queue<Node>q;
q.push(nod);
while (!q.empty()) {
auto nod = q.front();
int fa = nod.id;
cout << "序号=" << nod.id << " ";
for (int x : nod.up)cout << x << " ";
cout << " " << nod.mid << " ";
for (int x : nod.down)cout << x << " ";
cout << " 跳转到序号" << nod.fa << endl;
q.pop();
auto v = getNext(nod);
for (auto nod : v) {
int id = getId(nod);
if (s.find(id) == s.end()) {
s.insert(id);
nod.id = id;
nod.fa = fa;
q.push(nod);
}
}
}
}
int main() {
bfs();
return 0;
}
输出:
序号=0 70 60 50 40 30 20 90 0 50 60 70 90 20 30 40 跳转到序号0
序号=1 50 60 70 40 30 20 90 1 70 60 50 90 20 30 40 跳转到序号0
序号=2 70 90 20 40 30 20 90 1 70 60 50 30 40 50 60 跳转到序号0
序号=3 90 20 30 40 40 30 20 90 1 70 60 50 50 60 70 跳转到序号0
序号=4 30 40 50 60 40 30 20 90 1 70 60 50 70 90 20 跳转到序号0
序号=5 50 60 70 20 90 70 1 60 50 40 30 90 20 30 40 跳转到序号0
序号=6 70 90 20 20 90 70 1 60 50 40 30 30 40 50 60 跳转到序号0
序号=7 90 20 30 40 20 90 70 1 60 50 40 30 50 60 70 跳转到序号0
序号=8 30 40 50 60 20 90 70 1 60 50 40 30 70 90 20 跳转到序号0
序号=9 50 60 70 70 60 50 1 40 30 20 90 90 20 30 40 跳转到序号0
序号=10 70 90 20 70 60 50 1 40 30 20 90 30 40 50 60 跳转到序号0
。。。。。。
序号=646 90 50 40 50 20 30 60 20 1 40 70 70 90 30 60 跳转到序号612
序号=647 90 30 60 50 20 30 60 20 1 40 70 70 90 50 40 跳转到序号612
序号=648 20 50 40 70 30 60 30 60 1 90 70 20 40 90 50 跳转到序号617
序号=649 40 90 50 30 60 30 60 1 90 70 20 20 50 40 70 跳转到序号617
序号=650 20 50 40 70 90 70 20 1 30 60 30 60 40 90 50 跳转到序号617
序号=651 40 90 50 90 70 20 1 30 60 30 60 20 50 40 70 跳转到序号617
启发式策略(单节点)(V2)
cpp
//通用的数据缓存去重编号方案
template<typename T>
class GetSingleId
{
public:
int id(T x) //所有元素按照首次传入顺序编号0,1,2......
{
auto it = m.find(x);
if (it != m.end())return it->second;
mr[n] = x;
return m[x] = n++;
}
int num() //id()==num()-1表示是新元素,否则是重复元素
{
return n;
}
T getData(int id) //根据id获取元素数据
{
return mr[id];
}
private:
map<T, int>m;
map<int, T>mr;
int n = 0;
};
struct Node {
vector<int>up{ 70,60,50,40,30,20,90 };
int mid = 0;
vector<int>down{ 50,60,70,90,20,30,40 };
int ans = 0;
int id = 0;
int fa = 0;
};
int getId(vector<int> v) {
static map< vector<int>, int>m;
if (m.find(v) != m.end())return m[v];
int ans = m.size();
int len = v.size();
while (len--) {
v.push_back(v[0]);
v.erase(v.begin());
m[v] = ans;
}
return ans;
}
int getId(const Node& nod)
{
static GetSingleId<vector<int>> opt;
int id1 = getId(nod.up);
int id2 = getId(nod.down);
return opt.id(vector<int>{id1, nod.mid, id2});
}
vector<int> findId(const vector<int>& v)
{
vector<int>ans;
for (int i = 0; i < v.size(); i++) {
int s = 0;
for (int j = i; j < i + v.size(); j++) {
s += v[j % v.size()];
if (s >= 180)break;
}
if (s == 180)ans.push_back(i);
}
return ans;
}
vector<Node> getNext(const Node& nod)
{
vector<int> id1 = findId(nod.up);
vector<int> id2 = findId(nod.down);
vector<Node> ans;
for (int i : id1) {
for (int j : id2) {
vector<int>v1, v2;
int k1 = i, k2 = j, s1 = 0, s2 = 0;
while (s1 < 180) {
v1.push_back(nod.down[k2]);
s1 += nod.down[k2];
k2 = (k2 + 1) % nod.down.size();
}
while (s2 < 180) {
v2.push_back(nod.up[k1]);
s2 += nod.up[k1];
k1 = (k1 + 1) % nod.up.size();
}
while (k1 != i) {
v1.push_back(nod.up[k1]);
k1 = (k1 + 1) % nod.up.size();
}
while (k2 != j) {
v2.push_back(nod.down[k2]);
k2 = (k2 + 1) % nod.down.size();
}
ans.push_back({ v1,1 - nod.mid,v2,nod.ans + 1,0,0 });
}
}
return ans;
}
//假设对半翻转操作是长度为1,另外2个操作是长度为0,对整个图进行bfs搜出单源最短路径
vector<int> bfs(vector<Node>&vn)
{
vector<int> ans(652);
Node nod;
set<int>s;
s.insert(getId(nod));
queue<Node>q;
q.push(nod);
while (!q.empty()) {
auto nod = q.front();
int fa = nod.id;
int newAns = nod.ans + 1;
ans[fa] = nod.fa;
vn.push_back(nod);
q.pop();
auto v = getNext(nod);
for (auto nod : v) {
int id = getId(nod);
if (s.find(id) == s.end()) {
s.insert(id);
nod.id = id;
nod.fa = fa;
nod.ans = newAns;
q.push(nod);
}
}
}
return ans;
}
bool check56(const vector<int>& v)
{
int s50 = 0, s60 = 0;
for (auto x : v) {
if (x == 50)s50++;
if (x == 60)s60++;
}
if (s50 != s60)return false;
for (int i = 0; i < v.size(); i++) {
if (v[i] != 50 && v[i] != 60)continue;
if (v[(i + 1) % v.size()] != 110 - v[i] && v[(i + v.size() - 1) % v.size()] != 110 - v[i])return false;
}
return true;
}
bool check56(const Node& nod)
{
return check56(nod.up) && check56(nod.down);
}
int getLen(vector<Node>& vn, vector<int>& fa, int id)
{
int s = 0;
while (!check56(vn[id])) {
s++;
id = fa[id];
}
return s;
}
int main() {
vector<Node> vn;
vector<int> fa = bfs(vn);
for (int i = 0; i < fa.size(); i++) {
cout << i << " " << fa[i] << endl;
}
int max1 = 0, max2 = 0, maxs = 0;
for (int i = 0; i < fa.size(); i++) {
int x = getLen(vn, fa, i);
max1 = max(max1, x);
max2 = max(max2, vn[i].ans - x);
maxs = max(maxs, vn[i].ans);
}
cout << endl << "max:" << max1 << " " << max2 << " " << maxs;
return 0;
}
输出:
。。。。。。
643 609
644 612
645 612
646 612
647 612
648 617
649 617
650 617
651 617
max:10 6 13
所有状态的最速复原都可以分为2步,第一步是完成2组50+60的合并,第二步是彻底复原。其中的第一步,最多需要10次大操作,其中的第二步,最多需要6次大操作,而总共最多需要13次大操作。
启发式策略(双节点)(V2)
cpp
//通用的数据缓存去重编号方案
template<typename T>
class GetSingleId
{
public:
int id(T x) //所有元素按照首次传入顺序编号0,1,2......
{
auto it = m.find(x);
if (it != m.end())return it->second;
mr[n] = x;
return m[x] = n++;
}
int num() //id()==num()-1表示是新元素,否则是重复元素
{
return n;
}
T getData(int id) //根据id获取元素数据
{
return mr[id];
}
private:
map<T, int>m;
map<int, T>mr;
int n = 0;
};
struct Node {
vector<int>up{ 70,60,50,40,30,20,90 };
int mid = 0;
vector<int>down{ 50,60,70,90,20,30,40 };
int ans = 0;
int id = 0;
int fa = 0;
};
int getId(vector<int> v) {
static map< vector<int>, int>m;
if (m.find(v) != m.end())return m[v];
int ans = m.size();
int len = v.size();
while (len--) {
v.push_back(v[0]);
v.erase(v.begin());
m[v] = ans;
}
return ans;
}
int getId(const Node& nod)
{
static GetSingleId<vector<int>> opt;
int id1 = getId(nod.up);
int id2 = getId(nod.down);
return opt.id(vector<int>{id1, nod.mid, id2});
}
vector<int> findId(const vector<int>& v)
{
vector<int>ans;
for (int i = 0; i < v.size(); i++) {
int s = 0;
for (int j = i; j < i + v.size(); j++) {
s += v[j % v.size()];
if (s >= 180)break;
}
if (s == 180)ans.push_back(i);
}
return ans;
}
vector<Node> getNext(const Node& nod)
{
vector<int> id1 = findId(nod.up);
vector<int> id2 = findId(nod.down);
vector<Node> ans;
for (int i : id1) {
for (int j : id2) {
vector<int>v1, v2;
int k1 = i, k2 = j, s1 = 0, s2 = 0;
while (s1 < 180) {
v1.push_back(nod.down[k2]);
s1 += nod.down[k2];
k2 = (k2 + 1) % nod.down.size();
}
while (s2 < 180) {
v2.push_back(nod.up[k1]);
s2 += nod.up[k1];
k1 = (k1 + 1) % nod.up.size();
}
while (k1 != i) {
v1.push_back(nod.up[k1]);
k1 = (k1 + 1) % nod.up.size();
}
while (k2 != j) {
v2.push_back(nod.down[k2]);
k2 = (k2 + 1) % nod.down.size();
}
ans.push_back({ v1,1 - nod.mid,v2,nod.ans + 1,0,0 });
}
}
return ans;
}
//假设对半翻转操作是长度为1,另外2个操作是长度为0,对整个图进行bfs搜出单源最短路径
vector<int> bfs(vector<Node>&vn)
{
vector<int> ans(652);
Node nod;
set<int>s;
s.insert(getId(nod));
queue<Node>q;
q.push(nod);
while (!q.empty()) {
auto nod = q.front();
int fa = nod.id;
int newAns = nod.ans + 1;
ans[fa] = nod.fa;
vn.push_back(nod);
q.pop();
auto v = getNext(nod);
for (auto nod : v) {
int id = getId(nod);
if (s.find(id) == s.end()) {
s.insert(id);
nod.id = id;
nod.fa = fa;
nod.ans = newAns;
q.push(nod);
}
}
}
return ans;
}
bool check5656(const vector<int>& v)
{
int s50 = 0, s60 = 0;
for (auto x : v) {
if (x == 50)s50++;
if (x == 60)s60++;
}
if (s50 != s60)return false;
for (int i = 0; i < v.size(); i++) {
if (v[i] != 50 && v[i] != 60)continue;
if (v[(i + 1) % v.size()] != 110 - v[i] && v[(i + v.size() - 1) % v.size()] != 110 - v[i])return false;
}
return true;
}
bool check5656(const Node& nod)
{
return check5656(nod.up) && check5656(nod.down);
}
bool check56(const vector<int>& v)
{
for (int i = 0; i < v.size(); i++) {
if (v[i] != 50 && v[i] != 60)continue;
if (v[(i + 1) % v.size()] == 110 - v[i])return true;
}
return false;
}
bool check56(const Node& nod)
{
return check56(nod.up) || check56(nod.down);
}
void getLen(vector<Node>& vn, vector<int>& fa, int id, int &len1, int &len2)
{
int id0 = id;
len1 = 0, len2 = 0;
while (!check56(vn[id])) {
len1++;
id = fa[id];
}
while (!check5656(vn[id])) {
len2++;
id = fa[id];
}
cout << id0 << " " << len1 << " " << len2 << " " << vn[id0].ans - len1 - len2 << endl;
}
int main() {
vector<Node> vn;
vector<int> fa = bfs(vn);
for (int i = 0; i < fa.size(); i++) {
cout << i << " " << fa[i] << endl;
}
int max1 = 0, max2 = 0, max3 = 0, maxs = 0;
for (int i = 0; i < fa.size(); i++) {
int len1, len2;
getLen(vn, fa, i, len1, len2);
max1 = max(max1, len1);
max2 = max(max2, len2);
max3 = max(max3, vn[i].ans - len1 - len2);
maxs = max(maxs, vn[i].ans);
}
cout << endl << "max:" << max1 << " " << max2 << " " << max3 << " " << maxs;
return 0;
}
输出:
。。。。。。
644 0 10 3
645 7 3 3
646 7 3 3
647 0 10 3
648 7 3 3
649 7 3 3
650 7 3 3
651 7 3 3
max:7 10 6 13
其中,只有8种情况是中间为10的
直接挑出来:
序号=620 90 50 40 40 70 70 0 50 20 30 60 20 90 30 60 跳转到序号588
序号=623 90 30 60 50 20 30 60 20 0 40 70 70 90 50 40 跳转到序号588
序号=633 20 60 30 20 50 60 30 90 0 40 50 90 70 70 40 跳转到序号601
序号=634 70 70 40 40 50 90 0 60 30 90 20 60 30 20 50 跳转到序号601
序号=641 20 60 30 20 50 60 30 90 1 40 50 90 70 70 40 跳转到序号609
序号=642 70 70 40 40 50 90 1 60 30 90 20 60 30 20 50 跳转到序号609
序号=644 90 50 40 40 70 70 1 50 20 30 60 20 90 30 60 跳转到序号612
序号=647 90 30 60 50 20 30 60 20 1 40 70 70 90 50 40 跳转到序号612
显然,这8种情况只需要合适去重之后就会变成一种情况,但是我们不需要再去重了。
根据这8种情况,提取新的特征:70 70 90挨着了。
启发式策略(三节点)(最终策略)
cpp
//通用的数据缓存去重编号方案
template<typename T>
class GetSingleId
{
public:
int id(T x) //所有元素按照首次传入顺序编号0,1,2......
{
auto it = m.find(x);
if (it != m.end())return it->second;
mr[n] = x;
return m[x] = n++;
}
int num() //id()==num()-1表示是新元素,否则是重复元素
{
return n;
}
T getData(int id) //根据id获取元素数据
{
return mr[id];
}
private:
map<T, int>m;
map<int, T>mr;
int n = 0;
};
struct Node {
vector<int>up{ 70,60,50,40,30,20,90 };
int mid = 0;
vector<int>down{ 50,60,70,90,20,30,40 };
int ans = 0;
int id = 0;
int fa = 0;
};
int getId(vector<int> v) {
static map< vector<int>, int>m;
if (m.find(v) != m.end())return m[v];
int ans = m.size();
int len = v.size();
while (len--) {
v.push_back(v[0]);
v.erase(v.begin());
m[v] = ans;
}
return ans;
}
int getId(const Node& nod)
{
static GetSingleId<vector<int>> opt;
int id1 = getId(nod.up);
int id2 = getId(nod.down);
return opt.id(vector<int>{id1, nod.mid, id2});
}
vector<int> findId(const vector<int>& v)
{
vector<int>ans;
for (int i = 0; i < v.size(); i++) {
int s = 0;
for (int j = i; j < i + v.size(); j++) {
s += v[j % v.size()];
if (s >= 180)break;
}
if (s == 180)ans.push_back(i);
}
return ans;
}
vector<Node> getNext(const Node& nod)
{
vector<int> id1 = findId(nod.up);
vector<int> id2 = findId(nod.down);
vector<Node> ans;
for (int i : id1) {
for (int j : id2) {
vector<int>v1, v2;
int k1 = i, k2 = j, s1 = 0, s2 = 0;
while (s1 < 180) {
v1.push_back(nod.down[k2]);
s1 += nod.down[k2];
k2 = (k2 + 1) % nod.down.size();
}
while (s2 < 180) {
v2.push_back(nod.up[k1]);
s2 += nod.up[k1];
k1 = (k1 + 1) % nod.up.size();
}
while (k1 != i) {
v1.push_back(nod.up[k1]);
k1 = (k1 + 1) % nod.up.size();
}
while (k2 != j) {
v2.push_back(nod.down[k2]);
k2 = (k2 + 1) % nod.down.size();
}
ans.push_back({ v1,1 - nod.mid,v2,nod.ans + 1,0,0 });
}
}
return ans;
}
//假设对半翻转操作是长度为1,另外2个操作是长度为0,对整个图进行bfs搜出单源最短路径
vector<int> bfs(vector<Node>&vn)
{
vector<int> ans(652);
Node nod;
set<int>s;
s.insert(getId(nod));
queue<Node>q;
q.push(nod);
while (!q.empty()) {
auto nod = q.front();
int fa = nod.id;
int newAns = nod.ans + 1;
ans[fa] = nod.fa;
vn.push_back(nod);
q.pop();
auto v = getNext(nod);
for (auto nod : v) {
int id = getId(nod);
if (s.find(id) == s.end()) {
s.insert(id);
nod.id = id;
nod.fa = fa;
nod.ans = newAns;
q.push(nod);
}
}
}
return ans;
}
bool check5656(const vector<int>& v)
{
int s50 = 0, s60 = 0;
for (auto x : v) {
if (x == 50)s50++;
if (x == 60)s60++;
}
if (s50 != s60)return false;
for (int i = 0; i < v.size(); i++) {
if (v[i] != 50 && v[i] != 60)continue;
if (v[(i + 1) % v.size()] != 110 - v[i] && v[(i + v.size() - 1) % v.size()] != 110 - v[i])return false;
}
return true;
}
bool check5656(const Node& nod)
{
return check5656(nod.up) && check5656(nod.down);
}
bool check56(const vector<int>& v)
{
for (int i = 0; i < v.size(); i++) {
if (v[i] != 50 && v[i] != 60)continue;
if (v[(i + 1) % v.size()] == 110 - v[i])return true;
}
return false;
}
bool check56(const Node& nod)
{
return check56(nod.up) || check56(nod.down);
}
bool check779(const vector<int>& v)
{
for (int i = 0; i < v.size(); i++) {
if (v[i] != 90)continue;
if (v[(i + 1) % v.size()] == 70 && v[(i + 2) % v.size()] == 70)return false;
if (v[(i + v.size() - 1) % v.size()] == 70 && v[(i + v.size() - 2) % v.size()] == 70)return false;
}
return true;
}
bool check779(const Node& nod)
{
return check779(nod.up) && check779(nod.down);
}
void getLen(vector<Node>& vn, vector<int>& fa, int id, int &len1, int &len2, int &len3)
{
int id0 = id;
len1 = 0, len2 = 0, len3 = 0;
while (!check779(vn[id])) {
len1++;
id = fa[id];
}
while (!check56(vn[id])) {
len2++;
id = fa[id];
}
while (!check5656(vn[id])) {
len3++;
id = fa[id];
}
cout << id0 << " " << len1 << " " << len2 << " " <<len3<<" "<< vn[id0].ans - len1 - len2 -len3<< endl;
}
int main() {
vector<Node> vn;
vector<int> fa = bfs(vn);
for (int i = 0; i < fa.size(); i++) {
cout << i << " " << fa[i] << endl;
}
int max1 = 0, max2 = 0, max3 = 0, max4=0, maxs = 0;
for (int i = 0; i < fa.size(); i++) {
int len1, len2, len3;
getLen(vn, fa, i, len1, len2,len3);
max1 = max(max1, len1);
max2 = max(max2, len2);
max3 = max(max3, len3);
max4 = max(max4, vn[i].ans - len1 - len2-len3);
maxs = max(maxs, vn[i].ans);
}
cout << endl << "max:" << max1 << " " << max2 << " " << max3 << " " << max4 <<" "<< maxs;
return 0;
}
输出:
。。。。。。
640 1 6 3 3
641 1 6 3 3
642 1 6 3 3
643 1 6 3 3
644 1 6 3 3
645 1 6 3 3
646 1 6 3 3
647 1 6 3 3
648 0 7 3 3
649 0 7 3 3
650 0 7 3 3
651 0 7 3 3
max:1 7 4 6 13
所有状态的最速复原都可以分为4步,第一步是把70+70+90这个组合给拆开,第二步是完成1组50+60的合并,第三步是完成2组50+60的合并,第四步是彻底复原。
这四步分别最多需要1次、7次、4次、6次大操作,而总共最多需要13次大操作。
{1 7 4 6}这几个数字已经比较小了,所以具备了实际可用的启发功能。
亲测好用,至此,研究工作告一段落。