puzzle(0334)双面数局

一,双面数局

最强大脑 同款项目

二,计算机求解

1,交换公式

参考交换公式自动推导V6

2,通用操作

cpp 复制代码
vector<Opt> getOpts(int n)
{
	vector<int>v0;
	for (int i = 0; i < n*n * 2; i++)v0.push_back(i);
	vector<Opt>ans;
	for (int i = 0; i < n; i++) {
		string optName = "第";
		optName += std::to_string(i + 1);
		optName += "行往右";
		vector<int>v = v0;
		int s1 = i * n, s2 = i * n + n * n;
		vector<int>nums;
		for (int i = s1; i < s1 + n; i++)nums.push_back(i);
		for (int i = s2; i < s2 + n; i++)nums.push_back(i);
		for (int i = 0; i < nums.size(); i++)v[nums[(i + 1) % nums.size()]] = nums[i];
		Opt opt{ { v } ,optName };
		ans.push_back(opt);
	}
	for (int i = 0; i < n; i++) {
		string optName = "第";
		optName += std::to_string(i + 1);
		optName += "列往下";
		vector<int>v = v0;
		int s1 = i, s2 = n * n * 2 - i - 1;
		vector<int>nums;
		for (int i = s1; i < s1 + n * n; i += n)nums.push_back(i);
		for (int i = s2; i > s2 - n * n; i -= n)nums.push_back(i);
		for (int i = 0; i < nums.size(); i++)v[nums[(i + 1) % nums.size()]] = nums[i];
		Opt opt{ { v } ,optName };
		ans.push_back(opt);
	}
	return ans;
}

3,n=2

cpp 复制代码
int main()
{
	int n = 2;
	CubeBlock block1(0, n * n * 2);
	vector<CubeBlock>b = vector<CubeBlock>{ block1 };
	vector<Opt> v = getOpts(n);
	CubeOpt op1(b, v[0]);
	CubeOpt op2(b, v[1]);
	CubeOpt op3(b, v[2]);
	CubeOpt op4(b, v[3]);
	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, 2, 2);
	return 0;
}

输出:

2,1,0,3,4,5,6,7,

0第1行往右 0第1行往右 1第2行往右 2第1列往下 0第1行往右 1第2行往右 2第1列往下 1第2行往右 2第1列往下 0第1行往右 3第2列往下

这是交换0和2的公式

4,n=3

cpp 复制代码
int main()
{
	int n = 3;
	CubeBlock block1(0, n * n * 2);
	vector<CubeBlock>b = vector<CubeBlock>{ block1 };
	vector<Opt> v = getOpts(n);
	CubeOpt op1(b, v[0]);
	CubeOpt op2(b, v[1]);
	CubeOpt op3(b, v[2]);
	CubeOpt op4(b, v[3]);
	CubeOpt op5(b, v[4]);
	CubeOpt op6(b, v[5]);
	vector<CubeOpt>opts = { op1,op2,op3,op4,op5,op6 };
	for (int i = 0; i < opts.size(); i++)mans[i] = opts[i].getName();
	Cube cube(b, opts);
	cube.bfs(0, 2, 2);
	return 0;
}

输出:

0,1,7,3,4,5,6,2,8,9,10,11,12,13,14,15,16,17,

0第1行往右 0第1行往右 4第2列往下 1第2行往右 1第2行往右 1第2行往右 4第2列往下 4第2列往下 0第1行往右 0第1行往右 0第1行往右 0第1行往右 0第1行往右 1第2行往右 1第2行往右 0第1行往右 0第1行往右 0第1行往右 0第1行往右 0第1行往右 1第2行往右

这是交换2和7的公式

化简结果:

第1行往右 *2

第2列往下

第2行往右*3

第2列往下*2

第1行往左*2

第2行往右*3

5,n=4

代码1:略

运行结果:得到0 18 19 23交换的公式(不是1个4阶置换,而是2个2阶置换)

代码2:

cpp 复制代码
int main()
{
	int n = 4;
	CubeBlock block1(0, n * n * 2);
	vector<CubeBlock>b = vector<CubeBlock>{ block1 };
	vector<Opt> v = getOpts(n);
	CubeOpt op1(b, v[0]);
	CubeOpt op2(b, v[1]);
	CubeOpt op3(b, v[2]);
	CubeOpt op4(b, v[3]);
	CubeOpt op5(b, v[4]);
	CubeOpt op6(b, v[5]);
	CubeOpt op7(b, v[6]);
	CubeOpt op8(b, v[7]);
	Opt opt9{ { {19,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,23,0,20,21,22,18,24,25,26,27,28,29,30,31} } ,"【1下1右1上1左】" };
	CubeOpt op9(b, opt9);
	vector<CubeOpt>opts = { op1,op2,op3,op4,op5,op6,op7,op8,op9 };
	for (int i = 0; i < opts.size(); i++)mans[i] = opts[i].getName();
	Cube cube(b, opts);
	cube.bfs(0, 2, 3);
	return 0;
}

输出:

0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,21,19,20,22,18,23,24,25,26,27,28,29,30,31,

1第2行往右 6【1下1右1上1左】 1第2行往右 6【1下1右1上1左】 1第2行往右 1第2行往右 1第2行往右 1第2行往右 1第2行往右 1第2行往右

这是18-22-21三者轮换(顺时针旋转)的公式

化简结果:

第2行往右

【1下1右1上1左】

第2行往右

【1下1右1上1左】

第2行往左*2

我们把这个公式记作三轮换公式

代码3:

cpp 复制代码
int main()
{
	int n = 4;
	CubeBlock block1(0, n * n * 2);
	vector<CubeBlock>b = vector<CubeBlock>{ block1 };
	vector<Opt> v = getOpts(n);
	CubeOpt op1(b, v[0]);
	CubeOpt op2(b, v[1]);
	CubeOpt op3(b, v[2]);
	CubeOpt op4(b, v[3]);
	CubeOpt op5(b, v[4]);
	CubeOpt op6(b, v[5]);
	CubeOpt op7(b, v[6]);
	CubeOpt op8(b, v[7]);
	Opt opt9{ { {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,21,19,20,22,18,23,24,25,26,27,28,29,30,31} } ,"三轮换" };
	CubeOpt op9(b, opt9);
	vector<CubeOpt>opts = { op2,op9 };
	for (int i = 0; i < opts.size(); i++)mans[i] = opts[i].getName();
	Cube cube(b, opts);
	cube.bfs(0, 2, 2);
	return 0;
}

输出:

0,1,2,3,4,6,5,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,

0第2行往右 1三轮换 0第2行往右 0第2行往右 1三轮换 0第2行往右 0第2行往右 0第2行往右 1三轮换 0第2行往右 0第2行往右 1三轮换 0第2行往右

这是交换5和6的公式

化简结果:

第2行往右

【2右1下1右1上1左】 *4

第2行往右

【2右1下1右1上1左】 *4

第2行往左

其中,2右就是第2行往右,以此类推。

同理,还有交换4和7的公式

第2行往右*3

【1下1右1上1左】

第2行往右

【1下1右1上1左】

第2行往右 *2

【1下1右1上1左】

第2行往右

【1下1右1上1左】

第2行往左*2

【1下1右1上1左】

第2行往右

【1下1右1上1左】

第2行往右 *2

【1下1右1上1左】

第2行往右

【1下1右1上1左】

第2行往右

【1下1右1上1左】

第2行往右

【1下1右1上1左】

第2行往左*2

三,高阶场景

前面的校验,基本上已经形成固定的模式了,只需要数字改一改就能得到高阶的公式了。

和魔方不同的是,魔方是公式本身进行微调即可得到新公式,而双面数局是产生n=k的公式的代码微调即可得到产生n=k+1的公式的代码,但n=k的公式和n=k+1的公式之间差别还是挺大的。

1,通用操作

我们把"1下1右1上1左"这个小公式进行参数化,避免手动输入置换表

cpp 复制代码
vector<Opt> getOpts(int n)
{
	vector<int>v0;
	for (int i = 0; i < n*n * 2; i++)v0.push_back(i);
	vector<Opt>ans;
	for (int i = 0; i < n; i++) {
		string optName = "第";
		optName += std::to_string(i + 1);
		optName += "行往右";
		vector<int>v = v0;
		int s1 = i * n, s2 = i * n + n * n;
		vector<int>nums;
		for (int i = s1; i < s1 + n; i++)nums.push_back(i);
		for (int i = s2; i < s2 + n; i++)nums.push_back(i);
		for (int i = 0; i < nums.size(); i++)v[nums[(i + 1) % nums.size()]] = nums[i];
		Opt opt{ { v } ,optName };
		ans.push_back(opt);
	}
	for (int i = 0; i < n; i++) {
		string optName = "第";
		optName += std::to_string(i + 1);
		optName += "列往下";
		vector<int>v = v0;
		int s1 = i, s2 = n * n * 2 - i - 1;
		vector<int>nums;
		for (int i = s1; i < s1 + n * n; i += n)nums.push_back(i);
		for (int i = s2; i > s2 - n * n; i -= n)nums.push_back(i);
		for (int i = 0; i < nums.size(); i++)v[nums[(i + 1) % nums.size()]] = nums[i];
		Opt opt{ { v } ,optName };
		ans.push_back(opt);
	}
	string optName = "1下1右1上1左";
	vector<int>v = v0;
	v[0] = n * n + n - 1, v[n * n + n - 1] = 0;
	v[n * n + n - 2] = n * n + n * 2 - 1, v[n * n + n * 2 - 1] = n * n + n - 2;
	Opt opt{ { v } ,optName };
	ans.push_back(opt);
	return ans;
}

2,n=5

代码1:

cpp 复制代码
int main()
{
	int n = 5;
	CubeBlock block1(0, n * n * 2);
	vector<CubeBlock>b = vector<CubeBlock>{ block1 };
	vector<Opt> v = getOpts(n);
	CubeOpt op1(b, v[0]);
	CubeOpt op2(b, v[1]);
	CubeOpt op3(b, v[2]);
	CubeOpt op4(b, v[3]);
	CubeOpt op5(b, v[4]);
	CubeOpt op6(b, v[5]);
	CubeOpt op7(b, v[6]);
	CubeOpt op8(b, v[7]);
	CubeOpt op9(b, v[8]);
	CubeOpt op10(b, v[9]);
	CubeOpt op11(b, v[10]);
	vector<CubeOpt>opts = { op1,op2,op11 };
	for (int i = 0; i < opts.size(); i++)mans[i] = opts[i].getName();
	Cube cube(b, opts);
	cube.bfs(0, 2, 3);
	return 0;
}

输出:

0,1,2,3,4,28,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,34,29,30,31,32,33,5,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,

1第2行往右 1第2行往右 1第2行往右 1第2行往右 1第2行往右 1第2行往右 1第2行往右 1第2行往右 1第2行往右 21下1右1上1左 1第2行往右 21下1右1上1左

这是一个三轮换的公式。

化简结果:

第2行往左

【1下1右1上1左】

第2行往右

【1下1右1上1左】

代码2:

cpp 复制代码
int main()
{
	int n = 5;
	CubeBlock block1(0, n * n * 2);
	vector<CubeBlock>b = vector<CubeBlock>{ block1 };
	vector<Opt> v = getOpts(n);
	CubeOpt op1(b, v[0]);
	CubeOpt op2(b, v[1]);
	CubeOpt op3(b, v[2]);
	CubeOpt op4(b, v[3]);
	CubeOpt op5(b, v[4]);
	CubeOpt op6(b, v[5]);
	CubeOpt op7(b, v[6]);
	CubeOpt op8(b, v[7]);
	CubeOpt op9(b, v[8]);
	CubeOpt op10(b, v[9]);
	CubeOpt op11(b, v[10]);
	Opt opt{ { {0,1,2,3,4,28,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,34,29,30,31,32,33,5,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49} } ,"三轮换" };
	CubeOpt op12(b, opt);
	vector<CubeOpt>opts = { op2,op12 };
	for (int i = 0; i < opts.size(); i++)mans[i] = opts[i].getName();
	Cube cube(b, opts);
	cube.bfs(0, 2, 2);
	return 0;
}

输出1:

0,1,2,3,4,5,6,8,7,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,

0第2行往右 0第2行往右 1三轮换 0第2行往右 0第2行往右 1三轮换 0第2行往右 0第2行往右 1三轮换 0第2行往右 0第2行往右 0第2行往右 1三轮换 0第2行往右 0第2行往右 1三轮换

这是交换7和8的公式

化简结果:

【2右1下1右1上1左】 *6

第2行往右

【2右1下1右1上1左】 *4

输出2:

0,1,2,3,4,5,6,9,8,7,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,

0第2行往右 0第2行往右 1三轮换 0第2行往右 0第2行往右 1三轮换 0第2行往右 0第2行往右 1三轮换 0第2行往右 1三轮换 1三轮换 0第2行往右 0第2行往右 1三轮换 0第2行往右 0第2行往右 1三轮换

这是交换7和9的公式

化简结果:

【2右1下1右1上1左】 *6

第2行往左

【2右1下1右1上1左】 *2

第2行往左*2

【2右1下1右1上1左】 *6

相关推荐
_日拱一卒8 小时前
LeetCode:543二叉树的直径
算法·leetcode·职场和发展
jieyucx8 小时前
Go 数据结构入门:线性表、顺序表、链表
数据结构·链表·golang
汉克老师8 小时前
GESP2025年3月认证C++五级( 第一部分选择题(9-15))
c++·算法·高精度计算·二分算法·gesp5级·gesp五级
穿条秋裤到处跑8 小时前
每日一道leetcode(2026.04.28):获取单值网格的最小操作数
算法·leetcode·职场和发展
阿维的博客日记8 小时前
zset为什么要用到skiplist+Dict的数据结构
数据结构·skiplist
leoufung8 小时前
LeetCode 68. Text Justification 题解:贪心与实现细节
算法·leetcode·职场和发展
WL_Aurora9 小时前
【每日一题】前缀和
python·算法
汉克老师9 小时前
GESP2025年3月认证C++五级( 第二部分判断题(1-10))
c++·算法·分治算法·线性筛法·gesp5级·gesp五级
洛水水9 小时前
【力扣100题】17.K 个一组翻转链表
算法·leetcode·链表
洛水水9 小时前
【力扣100题】16.两两交换链表中的节点
算法·leetcode·链表