【排列问题】-四阶数独

【题目描述】

        数独是一种著名的益智游戏,这里讨论的是一种简化后的数独-四阶数独,给出一个4*4的方格,每个格子只能填写1-4的整数,要求每行每列和四等分更小的正方形部分刚好都由1-4组成,每行每列,每小块不能有重复的数字出现,共有多少种方案?

【输入格式】

        无

【输出格式】

        288,表示方案数

  其中一种方案


解题思路:

(1)如果要将4*4的方格填满,那么一共需要16个数,那么最坏的办法,套上16层循环 依次判断,但是不同于线性的排列,本题涉及到行,列还有块的分布,所以,这种方法低效且冗长

(2)那么利用深搜+回溯的方法,来将函数变的更为简练,可以创建一个DFS函数(x)x表示已填的数的个数,那么当x>16的时候,说明已经填满了4*4的方格,方案数增加,输出方案结果

(3)如何将每个数保存呢,可以利用一个ans数组来存储每一个数

(4)接下来到了最难的部分,如何标记每行每列和每小块,每行每列可以利用一个二维的bool数组,为什么要用二维的,行数用来标记每一行(每一列)出现的数字,列数相当于桶数组来打标记

如下图所示:表示第一个数字2,在第一行和第一列出现

 (5)那么第一个数在第一行第一列,第5个数在第二行第一列,如何根据x来设置所在的行号和列号呢?可以利用整除和取模的技巧

 (6)判断了行列号,那么可行性方案也就完成了两部分,接下来处理最难的,如何确定是第几块?观察下图:

当该元素是第1,2,5,6个时,(x-1)%4<=1&&(x<=6)

当该元素是第3,4,7,8个时,(x-1)%4>1&&(x<=8)

当该元素是第9,10,13,14个时,(x-1)%4<=1&&(6<x<=14)

当该元素是第11,12,15,16个时,(x-1)%4>1&&(8<x<=16)

一共才4小块,那么就可以这么确定编号


 (7)至此,最棘手的部分已经解决,然后利用回溯法来深搜即可


#include<bits/stdc++.h>
using namespace std;

int cnt,ans[20];
bool vis1[5][5];//标记每行出现的数字 
bool vis2[5][5];//标记每列出现的数字 
bool vis3[5][5];//标记每小块出现的数字

void dfs(int x)
{
	if(x>16)//如果取够了数 
	{
		cnt++;//方案数增加 
		for(int i=1;i<=16;i++)
		{
			cout<<ans[i]<<" ";
			
			if(i%4==0)
			cout<<endl;
		}//打印方案 
		return ;
	}
	
	int row=(x-1)/4+1;//判断该元素的行号 
	int col=(x-1)%4+1;//判断该元素的列号
	
	int num;//记录该元素属于第几块 
	if((x-1)%4<=1&&x<=6)//分类讨论 
	num=1; 
	else if((x-1)%4<=1&&x<=14)
	num=3;
	else if((x-1)%4>1&&x<=8)
	num=2;
	else
	num=4; 
	
	for(int i=1;i<=4;i++)
	{
		if(vis1[row][i]==0&&vis2[col][i]==0&&vis3[num][i]==0)//可行性方案 
		{
			ans[x]=i;//保存结果
			vis1[row][i]=1;
			vis2[col][i]=1;
			vis3[num][i]=1;//保存现场
			
			dfs(x+1);
			
			vis1[row][i]=0;
			vis2[col][i]=0;
			vis3[num][i]=0;//恢复现场
		}
	}
}
int main()
{
	dfs(1);
	cout<<cnt;//输出方案数 
	return 0;
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值