问题描述:
方格填数
如下的10个格子
+--+--+--+
| | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | |
+--+--+--+
(如果显示有问题,也可以参看下图)
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
首先,不必花心思考虑怎么把这个图形在程序中表现出来,一个一维数组就可以搞定,我们这样做:
自上而下,从左向右分别给这些单元格标记为 a[1],a[2],...,a[10]。
要做到题述要求,对于 a[1],只需要 a[1] 和 a[2],a[4],a[5],a[6] 之间的绝对值大于 1 即可。对其他位置亦是如此,如果填写的不符合要求就回溯,和深搜的思想一样,如果不是很理解深搜,请看这篇文章:
http://blog.csdn.net/eliminatedacmer/article/details/79334903
我们只需要将符合题意的结果找出来就可以了:
#include <iostream> #include <cmath> using namespace std; int count = 0; int a[12],b[12]; void Check() { if(abs(a[1]-a[2])>1 && abs(a[1]-a[4])>1 && abs(a[1]-a[5])>1 && abs(a[1]-a[6])>1 && abs(a[2]-a[3])>1 && abs(a[2]-a[5])>1 && abs(a[2]-a[6])>1 && abs(a[2]-a[7])>1 && abs(a[3]-a[6])>1 && abs(a[3]-a[7])>1 && abs(a[4]-a[5])>1 && abs(a[4]-a[8])>1 && abs(a[4]-a[9])>1 && abs(a[5]-a[6])>1 && abs(a[5]-a[8])>1 && abs(a[5]-a[9])>1 && abs(a[5]-a[10])>1 && abs(a[6]-a[7])>1 && abs(a[6]-a[9])>1 && abs(a[6]-a[10])>1 && abs(a[7]-a[10])>1 && abs(a[8]-a[9])>1 && abs(a[9]-a[10])>1) { count++; } } void Fill_numbers(int x) { if(x > 10) { Check(); return; } for(int i = 0;i<10;i++) { if(b[i] == 0) { b[i] = 1; a[x] = i; Fill_numbers(x+1); b[i] = 0; } } } int main() { Fill_numbers(1); cout<<count; return 0; }
接下来是寒假作业,请读者体会这两者思路上的差异。
问题描述:
寒假作业
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
(如果显示不出来,可以参见下图)
每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
以及:
7 + 6 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5
就算两种解法。(加法,乘法交换律后算不同的方案)
你一共找到了多少种方案?
请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。
对于这个问题我们很容易联想到上面那种解法,即:
#include <iostream> #define _MAX 13 using namespace std; int count = 0; int num[_MAX]; int vis[_MAX]; void dfs(int n) { int i = 0; if (n >= _MAX) { if (num[0] + num[1] == num[2] && num[3] - num[4] == num[5]&&num[6] * num[7] == num[8]&&num[10] * num[11] == num[9]) count++; return ; } for (; i < _MAX; i++) { if (!vis[i]) { vis[i] = 1; num[n] = i + 1; dfs(n + 1); vis[i] = 0; } } return ; } int main() { dfs(0); cout<<count; return 0; }
这种做法当然是正确的,但是如果你运行了一遍就会知道,它要得出正确的结果,需要长达几分钟的运行时间,因为我们是在所有数都填好之后才开始进行判断,而且这里有12个空,13个数字,因此大大增加了计算量,因此,我们需要优化算法,让它不要进行多余的计算,也就是说,如果第一个表达式都不满足的情况下,以后所有后续的填数工作我们都不需要做了。即:
#include <iostream> #define _MAX 13 using namespace std; int count = 0; int num[_MAX]; int vis[_MAX]; int Check(int n) { if (n == 2) { if (num[0] + num[1] == num[2]) { return 1; } } else if (n == 5) { if (num[3] - num[4] == num[5]) { return 1; } } else if (n == 8) { if (num[6] * num[7] == num[8]) { return 1; } } else if (n == 11) { if (num[10] * num[11] == num[9]) { count++; return 1; } } else { return 1; } return 0; } void dfs(int n) { int i = 0; if (n >= _MAX) { return ; } for (; i < _MAX; i++) { if (!vis[i]) { vis[i] = 1; num[n] = i + 1; if (!Check(n)) { vis[i] = 0; continue; } dfs(n + 1); vis[i] = 0; } } return ; } int main() { dfs(0); cout<<count; return 0; }