puzzle(0332)数字拼图旋转、九鼎之局、旋转数独

目录

一,数字拼图——旋转

1,手动求解

2,计算机求解

二,九鼎之局

三,旋转数独

1,规则

2,解法

3,轮换对称性

4,计算机求解

4.1已有代码

4.2 修改字符串输入方式、判定是否有解

4.3 求标准数独的9个九宫格的全排列空间的等价类个数。

4.4 遍历9个九宫格的位置

4.5 枚举9个九宫格的每种位置是否数独有解

4.6完整代码


一,数字拼图——旋转

数字华容道小游戏中的旋转模式

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";  这一行需要每次手动更新,其他代码不用动。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值