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

来源:互联网 发布:python 分词 相似度 编辑:程序博客网 时间:2024/05/16 08:52

在练习算法的时候,看见了这个题,利用递归回溯的方法,解开了这个题

问题描述:

方格填数


如下的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;//令当前的这个格子的数字为knum[k]=true;//令这个数字为已使用状态}elsecontinue;//如果当前的数字已经使用了,那么跳过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;}



阅读全文
0 0
原创粉丝点击