您的位置:首页 > 编程语言 > C语言/C++

2016年第七届蓝桥杯C/C++A组第三题---方格填数

2017-10-13 20:45 281 查看
在练习算法的时候,看见了这个题,利用递归回溯的方法,解开了这个题

问题描述:

方格填数

如下的10个格子



填入0~9的数字。要求:连续的两个数字不能相邻。

(左右、上下、对角都算相邻)

一共有多少种可能的填数方案?

请填写表示方案数目的整数。

注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。


以上就是问题的描述,第一感觉是枚举,但是想想,枚举可能超时,而且不好写,进而转变为其他的思路。

我们可以将这个问题分解为规模更小的子问题。例如已经填好了k个格子,在k个格子的基础上,我们进行处理问题,这样很容易就想到了递归的方法。

我们首先将格子规范化为下图这样



这样做的好处是,在判断当前数字和周围数字是否相邻的时候,可以采取统一的操作,即遍历以其自己为中心的9个方格,当然在遍历到其自身的时候跳过。

多增加的格子里的数字和所填的数字始终不会相邻,这样就不会对结果造成影响,而且可以规范判断时的操作。

以下是完整代码,代码后有注释

#include <iostream>
#include <math.h>
using namespace std;
int a[5][6];//开辟数组,为了保持统一性,在原来的方格的上下左右都新添了一行
bool num[10];//存放0-9这个10个数字的使用情况
int p=0;//记录方法数
bool flag = true;//标记当前的填法是否成功
void judge(int i,int j)
{
if (i == 3 && j == 4)//当填到第a[3][4]的时候,成功,因为图中的格子只到a[3][3]
{
p++;
return;
}
for (int k=0;k<=9;k++)//遍历10个数字
{
flag = true;
if (num[k]==false)//当前的数字没有被使用
{
a[i][j] = k;//令当前的这个格子的数字为k
num[k]=tr
4000
ue;//令这个数字为已使用状态
}
else
continue;//如果当前的数字已经使用了,那么跳过
for (int m = -1; m <= 1; m++)//如果当前的数字可以使用,那么检验自己周围的格子,看看是否满足条件,算上自己应该有9个格子,以自己为中心
{
for (int n = -1; n <= 1; n++)
{
if (m == 0 && n == 0)//如果要检查的格子为自身,直接跳过
continue;
if (abs(a[i][j] - a[i + m][j + n]) == 1)//绝对值相差为1,意味着为连续数字
{
num[k] = false;//当前使用的数字被还回去
flag = false;//当前方法不成功
}
}
}
if (flag == false)//如果当前方法不成功,那么继续尝试下一个数字
continue;
else//如果成功则继续下一个数字
{
if (j == 4)
{
judge(i + 1, 1);//当到达最右边的时候,重新进入下一行的考察
num[k] = false;//返回的时候,把占用的数字还回去,因为当返回的时候,意味以当前这个k延伸出去的所有解法已经没有
//所以要将当前的这个格子的数字调整为k+1,所以刚刚使用的k应该被还回去,所以设置k的状态为false未使用
}
else
{
judge(i, j + 1);//没有到达最右的时候,向右
num[k] = false;//返回的时候,把占用的数字还回去,道理同上
}
}
}
a[i][j] = -10;//当前这个格子的问题结束了,把格子置为未使用状态
}

int main() {
int i, j;
for (i=0;i<10;i++)//初始化数字状态数组
num[i] = false;

for (i=0;i<5;i++)//初始化格子,都是未使用状态,-10也可以是别的数字,只要别和0-9连续
for (j=0;j<6;j++)
a[i][j] = -10;

judge(1, 2);//从a[1][2]开始填
cout << p<<endl;//输出方法总数
cin >> p;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: