目录
一,数字拼图——旋转
数字华容道小游戏中的旋转模式
1,手动求解
很容易把第一行和第一列搞定,关键是右下角四个怎么排序。
出现这种情况,需要把5和6反过来。显然只要知道怎么交换5和6,就能轻松应付所有情况了。
经过几次尝试,我把公式找出来了,左上的旋转按钮是不需要的,所以我把其他三个按钮分别叫做上左右。
公式就是上上左上右上上右右左右右右左右右右,这17个操作下来,就把5和6对换了,其他的不动。
对于更高阶的情况,都可以直接化成3*3的情况,方法和数字拼图——滑动的方法一样。
2,计算机求解
void turn0(vector<int>&v)
{
int x=v[0];
v[0]=v[3],v[3]=v[4],v[4]=v[1],v[1]=x;
}
void turn1(vector<int>&v)
{
int x=v[1];
v[1]=v[4],v[4]=v[5],v[5]=v[2],v[2]=x;
}
void turn2(vector<int>&v)
{
int x=v[3];
v[3]=v[6],v[6]=v[7],v[7]=v[4],v[4]=x;
}
void turn3(vector<int>&v)
{
int x=v[4];
v[4]=v[7],v[7]=v[8],v[8]=v[5],v[5]=x;
}
void turn(int id,vector<int>&v)
{
if(id==0)turn0(v);
if(id==1)turn1(v);
if(id==2)turn2(v);
if(id==3)turn3(v);
}
vector<int> change56{1,1,2,1,3,1,1,3,3,2,3,3,3,2,3,3,3};
bool del3(vector<int>&v)
{
if(v.size()<4)return false;
for(int i=0;i+3<v.size();i++){
if(v[i]==3 && v[i+1]==3 && v[i+2]==3 && v[i+3]==3){
for(int j=i;j+4<v.size();j++)v[j]=v[j+4];
v.resize(v.size()-4);
return true;
}
}
return false;
}
#define MOVE(id) opts.push_back(id),turn(id,v);
//输入123456789的排列,输出操作序列,0123分别是左上 右上 左下 右下
vector<int> solve33(vector<int>v)
{
vector<int>opts;
if(v[2]==1)MOVE(1);
if(v[5]==1)MOVE(3);
if(v[8]==1)MOVE(3);
if(v[7]==1)MOVE(2);
if(v[6]==1)MOVE(2);
while(v[0]!=1)MOVE(0);
if(v[6]==3)MOVE(2);
if(v[3]==3)MOVE(2);
if(v[8]==3)MOVE(3);
if(v[7]==3)MOVE(3);
while(v[1]!=3)MOVE(1);
if(v[2]==2){
MOVE(1);
MOVE(1);
MOVE(2);
MOVE(2);
MOVE(2);
MOVE(1);
MOVE(1);
MOVE(2);
MOVE(1);
}else{
if(v[6]==2)MOVE(2);
if(v[3]==2)MOVE(2);
while(v[4]!=2)MOVE(3);
MOVE(1);
}
//至此是123******
if(v[6]==4)MOVE(2);
if(v[3]==4)MOVE(2);
while(v[8]!=4)MOVE(3);
if(v[5]==7){
MOVE(3);
MOVE(2);
MOVE(3);
MOVE(2);
}else{
while(v[3]!=7)MOVE(2);
MOVE(3);
MOVE(3);
MOVE(2);
MOVE(2);
MOVE(2);
}
//至此是1234**7**
while(v[4]!=5)MOVE(3);
if(v[7]==6){
MOVE(3);
for(auto x:change56)MOVE(x);
}
if(v[8]==6){
for(auto x:change56)MOVE(x);
MOVE(3);
MOVE(3);
MOVE(3);
}
//至此是1234567**
if(v[7]==9){
MOVE(3);
MOVE(3);
for(auto x:change56)MOVE(x);
MOVE(3);
MOVE(3);
}
while(del3(opts));
return opts;
}
二,九鼎之局
最强大脑同款项目。
就是数字拼图(旋转),使得每一行每一列都是9个不同的数字。
我的初始思路是贪心原则,一行行往下弄,最后只需要一个单独交换2个格子的公式即可。
但是也可能会变成这样:
右下角的9个无论怎么互换都不行了。
所以我的思路更新成,把右下角留出3个数,每个数3个。
即先按照贪心方法完成其他8个宫,最后一个宫是3个数各3个,就很容易完成,甚至不需要单独交换2格的公式。
最强大脑的同款项目中, 第一次达到榜一成就。
不过这个思路还是有一点偶然性,于是我把最强大脑选手的2个思路试了一下,即九宫格法和斜线法。
九宫格法:
斜线法:
这2个方法确实简单且高效,不会出现难搞的情况。
三,旋转数独
最强大脑同款项目。
1,规则
使用四个旋转按钮和填充数字,使得变成一个完整的数独。
2,解法
(1)单个九宫格可以填充的数字就填充
这个case里面没有,那就跳过
(2)选择一个出现较多的数字,把它的9个位置都确定下来
这里的2就全部确定了
(3)选择一个数字较多的九宫格,确定和它在同一行的2个九宫格,把这3个九宫格都移到第一行
这里第一行的3个九宫格就确定在同一行了
(4)剩下的6个九宫格里面,再选择一个数字较多的九宫格,确定和它在同一行的2个九宫格,把这3个九宫格都移到第二行(第一行的3个九宫格位置不动)
这里的第二行的3个九宫格就确定在同一行了,那么第三行的3个九宫格也就确定在同一行了
(5)只根据行的信息和单个九宫格的信息,可以填充的数字就填充
这里的最右上角的九宫格就完成了
(6)第一行的3个九宫格位置固定不动,让第二行的3个九宫格之间互换,再让第三行的3个九宫格之间互换,使得数独有解
PS:同一行的3个九宫格之间如何交换,参考《数字拼图——旋转》里面的公式。
这里的9个九宫格位置就全部定下来了
(7)直接完成数独
直到这里,所有的数字都是确定的。
剩下的几个空格,不止一种填法,随便选择一种即可。
3,轮换对称性
我这个解法在2个地方都比较简洁,因为蕴含了轮换对称性。
参考我的轮换对称性总结:通用抽象概念
4,计算机求解
4.1已有代码
class DancingLink // 精确覆盖算法
class SearchWithGroupSum //分组数字搜索算法
string Sudoku(string s, char cEmpty = '.')
这2个类和1个函数的代码来自我的博客《十字交叉双向循环链表 dancing links》
因为输入的数独有可能是无解的,所以X算法要选V9拓展版。
4.2 修改字符串输入方式、判定是否有解
string Sudoku(vector<string>s,bool &flag)
{
string ans;
for(int i=0;i<9;i+=3){
string s1=s[i],s2=s[i+1],s3=s[i+2];
ans+=s1[0],ans+=s1[1],ans+=s1[2];
ans+=s2[0],ans+=s2[1],ans+=s2[2];
ans+=s3[0],ans+=s3[1],ans+=s3[2];
ans+=s1[3],ans+=s1[4],ans+=s1[5];
ans+=s2[3],ans+=s2[4],ans+=s2[5];
ans+=s3[3],ans+=s3[4],ans+=s3[5];
ans+=s1[6],ans+=s1[7],ans+=s1[8];
ans+=s2[6],ans+=s2[7],ans+=s2[8];
ans+=s3[6],ans+=s3[7],ans+=s3[8];
}
string ret = Sudoku(ans);
flag = true;
for(auto c:ret)if(c=='0')flag=false;
return ret;
}
把输入方式改成输入9个九宫格的字符串,出参flag表示是否有解。
4.3 求标准数独的9个九宫格的全排列空间的等价类个数。
求解:
(1)第一行第一个随便放,然后8个选2个放在第一行,顺序随意。C(8,1)*C(7,1)/2=28
(2)剩下6个分为2组,随便一组放第二行,另一组放第三行。C(6,3)*C(3,3)/2=10
(3)第二行排序,3!=6,第三行排序,3!=6
所以最终的等价类个数是28*10*6*6=10080
总结:
(1)9!是10080的36倍。实际上,每一个等价类都有36个对象,因为3行的排列有6种,3列的排列有6种,6*6=36。
(2)得到10080这个数字有2种方法,第一是C(8,1)*C(7,1)/2*C(6,3)*C(3,3)/2*3!*3!=10080,第二是9!/3!/3!=10080,虽然第二种更巧妙简单,但是第一种揭露了一个重要的细节,即如何进行DFS剪枝。
(3)不同剪枝方法的效率是不同的,上面的求解出10080的第一种方法,这是几乎是最优剪枝。因为10080个对象是必须要遍历的,而这里的方法基本上也就只遍历这10080个对象。不过我下面的编程实现,处于实现简单,遍历了10080*2个对象,性能也能接受。
4.4 遍历9个九宫格的位置
用123456789表示标准数独的9个九宫格,求10080个互不等价的对象。
//A66 / 2
vector<vector<int>> A66Div2(vector<int>v)
{
int mins = v[0];
for(auto x:v)mins=min(mins,x);
vector<vector<int>>ans;
for(int i=0;i<6;i++){
for(int j=0;j<6;j++){
if(j==i)continue;
for(int k=0;k<6;k++){
if(k==i || k==j)continue;
if(v[i]!=mins && v[j]!=mins && v[k]!=mins)continue;
for(int i2=0;i2<6;i2++){
if(i2==i||i2==j||i2==k)continue;
for(int j2=0;j2<6;j2++){
if(j2==i||j2==j||j2==k||j2==i2)continue;
for(int k2=0;k2<6;k2++){
if(k2==i||k2==j||k2==k||k2==i2||k2==j2)continue;
ans.push_back({v[i],v[j],v[k],v[i2],v[j2],v[k2]});
}
}
}
}
}
}
return ans;
}
vector<vector<int>> solve()
{
vector<vector<int>>ans;
vector<int>v;
v.resize(9);
v[0]=1;
for(int i=2;i<=9;i++){
for(int j=i+1;j<=9;j++){//把i和j随意放,理解成左边放小的右边放大的
v[1]=i,v[2]=j;
//剩下的6个元素,其实就是6的全排列,去掉其中一半的排列即可。
vector<int>v2;
for(int k=2;k<=9;k++)if(k!=i&&k!=j)v2.push_back(k);
vector<vector<int>>v3=A66Div2(v2);
for(auto v4:v3){
for(int i=3;i<9;i++)v[i]=v4[i-3];
ans.push_back(v);
}
}
}
return ans;
}
测试代码:
void main()
{
vector<vector<int>>ans = solve();
cout<<ans.size()<<endl<<endl;
for(auto v:ans){
cout<<v[0]<<" "<<v[1]<<" "<<v[2]<<endl;
cout<<v[3]<<" "<<v[4]<<" "<<v[5]<<endl;
cout<<v[6]<<" "<<v[7]<<" "<<v[8]<<endl;
cout<<endl;
}
}
运行结果:
省略后面很多行。
4.5 枚举9个九宫格的每种位置是否数独有解
void printAns(vector<string>s,vector<int>v,string ans)
{
for(auto i:v){
cout<<s[i-1]<<endl;
}
cout<<ans;
}
void myMain()
{
vector<vector<int>>ans = solve();
vector<string>s{
"...25..87",
"7.46....5",
".5..7...9",
"7..146.5.",
"196348.72",
"5...97...",
"4276.581.",
"98.74.2.6",
"362..19.4"
};
bool flag;
for(auto v:ans){
vector<string>vs;
for(int i=0;i<9;i++)vs.push_back(s[v[i]-1]);
string ret = Sudoku(vs,flag);
if(flag){
printAns(s,v,ret);
break;
}
}
}
代码里面的9个字符串,对应9个九宫格,需要手动填写到代码中。
可能会有多个解,我这里只求一个解。
4.6完整代码
#include <iostream>
#include <algorithm>
#include<climits>
#include <vector>
#include <map>
using namespace std;
class DancingLink // 精确覆盖算法
{
public:
DancingLink(int m, int n, int maxNum) //01矩阵的行、列、1的最大数量
{
this->m = m, this->n = n, maxNum += n + 1;
rhead.resize(m + 1), nums.resize(n + 1);
row.resize(maxNum), col.resize(maxNum);
up.resize(maxNum), down.resize(maxNum), lef.resize(maxNum), rig.resize(maxNum);
sc.resize(m), rows.resize(m);
for (int i = 0; i <= n; i++)
{
up[i] = i, down[i] = i;
lef[i] = i - 1, rig[i] = i + 1;
row[i] = 0, col[i] = i, nums[i] = 0;
}
lef[0] = n, rig[n] = 0;
nums[0] = INT_MAX/2;
key = n;
for (int i = 0; i <= m; i++)rhead[i] = 0;
}
void push(int r, int c)//新增坐标在(r,c)的一个节点
{
row[++key] = r, col[key] = c;
up[key] = c, down[key] = down[c];
up[down[c]] = key, down[c] = key;
if (rhead[r] == 0)rhead[r] = lef[key] = rig[key] = key;
else
{
lef[key] = rhead[r], rig[key] = rig[rhead[r]];
lef[rig[rhead[r]]] = key, rig[rhead[r]] = key;
}
nums[c]++;
}
vector<vector<int>> getAllAns()
{
return dfs(false);
}
vector<int> getAnyAns()
{
auto v = dfs(true);
if (v.size())return v[0];
return vector<int>{};
}
private:
vector<vector<int>> dfs(bool onlyOne)
{
vector<vector<int>>ans;
while (true) {
if (rig[0] == 0) {
rows.resize(rowsid);
ans.push_back(rows);
rows.resize(m);
if (onlyOne)return ans;
}
int c = min_element(nums.begin() + 1, nums.end()) - nums.begin();
if (rig[0] == 0)c = 0;
del(c);
while (true) {
c = down[c];
if (c > n)break;
reback(col[c]);
if (scid == 0)return ans;
c = sc[--scid];
rowsid--;
for (int j = rig[c]; j != c; j = rig[j])reback(col[j]);
}
sc[scid++] = c;//记录选中id
rows[rowsid++] = row[c];
for (int j = rig[c]; j != c; j = rig[j])del(col[j]);
}
return ans;
}
inline void del(int c)//删除第c列的所有元素和他们所在行的所有元素
{
lef[rig[c]] = lef[c], rig[lef[c]] = rig[c];
for (int i = down[c]; i != c; i = down[i])
for (int j = rig[i]; j != i; j = rig[j])
down[up[j]] = down[j], up[down[j]] = up[j], nums[col[j]]--;
nums[c] = INT_MAX/2;
}
inline void reback(int c)//完全回退del操作
{
lef[rig[c]] = rig[lef[c]] = c, nums[c] = 0;
for (int i = down[c]; i != c; i = down[i]) {
for (int j = rig[i]; j != i; j = rig[j])
down[up[j]] = up[down[j]] = j, nums[col[j]]++;
nums[c]++;
}
}
private:
int m, n, key;
vector<int>row, col;//每个节点的行,列
vector<int>rhead;//每行第一个节点的id
vector<int>up, down, lef, rig;//每个节点上下左右的节点id
vector<int>nums;//每一列的元素个数
vector<int>sc;
int scid = 0, rowsid = 0;
vector<int>rows;//覆盖选中的行,值的范围是从1到m
};
class SearchWithGroupSum //分组数字搜索算法
{
public:
SearchWithGroupSum(vector<vector<int>>& gridGroup, int row, int col, int low, int high) :gridGroup{ gridGroup },row { row }, col{ col },low{low},high{high}
{
anti.resize(row*col);
grid.resize(row*col);
for (int g = 0; g < gridGroup.size(); g++) {
for (int i = 0; i < gridGroup[g].size(); i++)anti[gridGroup[g][i]].push_back(g);
maxNum += gridGroup[g].size();
}
}
void setGrid(vector<int>& grid)//除了已知数字之外都填0,有type=1的格子时需要调用本接口
{
this->grid = grid;
}
void setType(vector<int>& type)//有type=1或-1的格子时需要调用本接口
{
this->type = type;
}
vector<int> getAnyAns()
{
int m = 0;
for (auto k : type) {
if (k == 0)m += high - low + 1;
else if (k == 1)m += 1;
}
int n = gridGroup.size()*(high - low + 1) + row * col;
DancingLink d(m, n, (maxNum+row*col)*(high-low+1));
int r = 0;
map<int, int>mrow;
mrow[0] = -1;
for (int i = 0; i < row*col; i++) {
if (type[i] == -1)continue;
int lw = low, hh = high;
if (type[i] == 1)lw = hh = grid[i];
for (int x = lw; x <= hh; x++) {
d.push(++r, i + 1);
for (auto k : anti[i]) {
d.push(r, k*(high - low + 1) + x - low + row * col + 1);
}
mrow[r] = i;
}
}
vector<int> ans = d.getAnyAns();
for (auto rowId : ans) {
int id = mrow[rowId];
grid[id] += type[id]?0:low;
while (id == mrow[rowId - 1])rowId--, grid[id]++;
}
return grid;
}
private:
int row, col;//网格行列数
int low, high;//每个格子填入数字的范围是[low,high], 限制一:low>0
vector<int>type;//标识所有格子类型,0是需要填数字,1是已知数字,-1是无效格子
vector<int>grid;//所有格子中的数字
vector<vector<int>>gridGroup;//每一组有哪些格子
vector<vector<int>>anti;//每个格子属于哪些组
int maxNum = 1;
};
string Sudoku(string s, char cEmpty = '.')
{
vector<vector<int>>gridGroup;
vector<int>v;
for (int i = 0; i < 9; i++) {
v.clear();
for (int j = 0; j < 9; j++)v.push_back(i * 9 + j);
gridGroup.push_back(v);
v.clear();
for (int j = 0; j < 9; j++)v.push_back(j * 9 + i);
gridGroup.push_back(v);
}
for (int i = 0; i < 3; i++)for (int j = 0; j < 3; j++) {
v.clear();
for (int r = i * 3; r < i * 3 + 3; r++)for (int c = j * 3; c < j * 3 + 3; c++)v.push_back(r * 9 + c);
gridGroup.push_back(v);
}
SearchWithGroupSum opt(gridGroup, 9, 9, 1, 9);
vector<int>grid(81);
vector<int>type(81);
for (int i = 0; i < 81; i++)if (s[i] != cEmpty)grid[i] = s[i] - '0', type[i] = 1;
opt.setGrid(grid);
opt.setType(type);
v = opt.getAnyAns();
string ans(81, '0');
for (int i = 0; i < 81; i++)ans[i] = v[i] + '0';
return ans;
}
string Sudoku(vector<string>s,bool &flag)
{
string ans;
for(int i=0;i<9;i+=3){
string s1=s[i],s2=s[i+1],s3=s[i+2];
ans+=s1[0],ans+=s1[1],ans+=s1[2];
ans+=s2[0],ans+=s2[1],ans+=s2[2];
ans+=s3[0],ans+=s3[1],ans+=s3[2];
ans+=s1[3],ans+=s1[4],ans+=s1[5];
ans+=s2[3],ans+=s2[4],ans+=s2[5];
ans+=s3[3],ans+=s3[4],ans+=s3[5];
ans+=s1[6],ans+=s1[7],ans+=s1[8];
ans+=s2[6],ans+=s2[7],ans+=s2[8];
ans+=s3[6],ans+=s3[7],ans+=s3[8];
}
string ret = Sudoku(ans);
flag = true;
for(auto c:ret)if(c=='0')flag=false;
return ret;
}
/*
(1)第一行第一个随便放,然后8个选2个放在第一行,顺序随意。C(8,1)*C(7,1)/2=28
(2)剩下6个分为2组,随便一组放第二行,另一组放第三行。C(6,3)*C(3,3)/2=10
(3)第二行排序,3!=6,第三行排序,3!=6
*/
//A66 / 2
vector<vector<int>> A66Div2(vector<int>v)
{
int mins = v[0];
for(auto x:v)mins=min(mins,x);
vector<vector<int>>ans;
for(int i=0;i<6;i++){
for(int j=0;j<6;j++){
if(j==i)continue;
for(int k=0;k<6;k++){
if(k==i || k==j)continue;
if(v[i]!=mins && v[j]!=mins && v[k]!=mins)continue;
for(int i2=0;i2<6;i2++){
if(i2==i||i2==j||i2==k)continue;
for(int j2=0;j2<6;j2++){
if(j2==i||j2==j||j2==k||j2==i2)continue;
for(int k2=0;k2<6;k2++){
if(k2==i||k2==j||k2==k||k2==i2||k2==j2)continue;
ans.push_back({v[i],v[j],v[k],v[i2],v[j2],v[k2]});
}
}
}
}
}
}
return ans;
}
vector<vector<int>> solve()
{
vector<vector<int>>ans;
vector<int>v;
v.resize(9);
v[0]=1;
for(int i=2;i<=9;i++){
for(int j=i+1;j<=9;j++){//把i和j随意放,理解成左边放小的右边放大的
v[1]=i,v[2]=j;
//剩下的6个元素,其实就是6的全排列,去掉其中一半的排列即可。
vector<int>v2;
for(int k=2;k<=9;k++)if(k!=i&&k!=j)v2.push_back(k);
vector<vector<int>>v3=A66Div2(v2);
for(auto v4:v3){
for(int i=3;i<9;i++)v[i]=v4[i-3];
ans.push_back(v);
}
}
}
return ans;
}
void turn0(vector<int>&v)
{
int x=v[0];
v[0]=v[3],v[3]=v[4],v[4]=v[1],v[1]=x;
}
void turn1(vector<int>&v)
{
int x=v[1];
v[1]=v[4],v[4]=v[5],v[5]=v[2],v[2]=x;
}
void turn2(vector<int>&v)
{
int x=v[3];
v[3]=v[6],v[6]=v[7],v[7]=v[4],v[4]=x;
}
void turn3(vector<int>&v)
{
int x=v[4];
v[4]=v[7],v[7]=v[8],v[8]=v[5],v[5]=x;
}
void turn(int id,vector<int>&v)
{
if(id==0)turn0(v);
if(id==1)turn1(v);
if(id==2)turn2(v);
if(id==3)turn3(v);
}
vector<int> change56{1,1,2,1,3,1,1,3,3,2,3,3,3,2,3,3,3};
bool del3(vector<int>&v)
{
if(v.size()<4)return false;
for(int i=0;i+3<v.size();i++){
if(v[i]==3 && v[i+1]==3 && v[i+2]==3 && v[i+3]==3){
for(int j=i;j+4<v.size();j++)v[j]=v[j+4];
v.resize(v.size()-4);
return true;
}
}
return false;
}
#define MOVE(id) opts.push_back(id),turn(id,v);
//输入123456789的排列,输出操作序列,0123分别是左上 右上 左下 右下
vector<int> solve33(vector<int>v)
{
vector<int>opts;
if(v[2]==1)MOVE(1);
if(v[5]==1)MOVE(3);
if(v[8]==1)MOVE(3);
if(v[7]==1)MOVE(2);
if(v[6]==1)MOVE(2);
while(v[0]!=1)MOVE(0);
if(v[6]==3)MOVE(2);
if(v[3]==3)MOVE(2);
if(v[8]==3)MOVE(3);
if(v[7]==3)MOVE(3);
while(v[1]!=3)MOVE(1);
if(v[2]==2){
MOVE(1);
MOVE(1);
MOVE(2);
MOVE(2);
MOVE(2);
MOVE(1);
MOVE(1);
MOVE(2);
MOVE(1);
}else{
if(v[6]==2)MOVE(2);
if(v[3]==2)MOVE(2);
while(v[4]!=2)MOVE(3);
MOVE(1);
}
//至此是123******
if(v[6]==4)MOVE(2);
if(v[3]==4)MOVE(2);
while(v[8]!=4)MOVE(3);
if(v[5]==7){
MOVE(3);
MOVE(2);
MOVE(3);
MOVE(2);
}else{
while(v[3]!=7)MOVE(2);
MOVE(3);
MOVE(3);
MOVE(2);
MOVE(2);
MOVE(2);
}
//至此是1234**7**
while(v[4]!=5)MOVE(3);
if(v[7]==6){
MOVE(3);
for(auto x:change56)MOVE(x);
}
if(v[8]==6){
for(auto x:change56)MOVE(x);
MOVE(3);
MOVE(3);
MOVE(3);
}
//至此是1234567**
if(v[7]==9){
MOVE(3);
MOVE(3);
for(auto x:change56)MOVE(x);
MOVE(3);
MOVE(3);
}
while(del3(opts));
return opts;
}
void printAns(vector<string>s,vector<int>v,string ans)
{
vector<int>x;
x.resize(9);
int num=0;
for(auto i:v){
cout<<s[i-1]<<endl;
x[i-1]=++num;
}
auto opts = solve33(x);
for(auto opt:opts)cout<<opt<<" ";
cout<<endl;
for(int i=0;i<81;i++){
cout<<ans[i];
if(i%9==8)cout<<endl;
}
}
void myMain()
{
vector<vector<int>>ans = solve();
string ss = "37..5827.264..11955.1.2.8..12.4.6.154...2..466.7..7.3.96.514....5..8.27..843..138";
string s1,s2,s3,s4,s5,s6,s7,s8,s9;
s1=s1+ss[0]+ss[1]+ss[2]+ss[9]+ss[10]+ss[11]+ss[18]+ss[19]+ss[20];
s2=s2+ss[3]+ss[4]+ss[5]+ss[12]+ss[13]+ss[14]+ss[21]+ss[22]+ss[23];
s3=s3+ss[6]+ss[7]+ss[8]+ss[15]+ss[16]+ss[17]+ss[24]+ss[25]+ss[26];
s4=s4+ss[27]+ss[28]+ss[29]+ss[36]+ss[37]+ss[38]+ss[45]+ss[46]+ss[47];
s5=s5+ss[30]+ss[31]+ss[32]+ss[39]+ss[40]+ss[41]+ss[48]+ss[49]+ss[50];
s6=s6+ss[33]+ss[34]+ss[35]+ss[42]+ss[43]+ss[44]+ss[51]+ss[52]+ss[53];
s7=s7+ss[54]+ss[55]+ss[56]+ss[63]+ss[64]+ss[65]+ss[72]+ss[73]+ss[74];
s8=s8+ss[57]+ss[58]+ss[59]+ss[66]+ss[67]+ss[68]+ss[75]+ss[76]+ss[77];
s9=s9+ss[60]+ss[61]+ss[62]+ss[69]+ss[70]+ss[71]+ss[78]+ss[79]+ss[80];
vector<string>s{
s1,s2,s3,s4,s5,s6,s7,s8,s9
};
bool flag;
for(auto v:ans){
vector<string>vs;
for(int i=0;i<9;i++)vs.push_back(s[v[i]-1]);
string ret = Sudoku(vs,flag);
if(flag){
printAns(s,v,ret);
break;
}
}
}
int main() {
myMain();
return 0;
}
其中,string ss = "37..5827.264..11955.1.2.8..12.4.6.154...2..466.7..7.3.96.514....5..8.27..843..138"; 这一行需要每次手动更新,其他代码不用动。