蓝桥杯 DFS经典题 —— 算式900、寒假作业(告别枚举法)

类似于 算式 900、寒假作业这种题目,可以直接暴力破解,但是它非常的浪费时间,而且程序不是太过于美观,很容易让我们对算法失去兴趣,今天,我们告别传统的暴力破解,使用伟大搜索算法 —— DFS(深度优先搜索) . . .
.
DFS 相关文章如下所示:
《算法笔记》—— “迷宫求解” 之 深度优先搜索(DFS)
《算法笔记》—— 图 “邻接矩阵” 的遍历(DFS、BFS)
在这里插入图片描述


算式900

题目: 小明的作业本上有道思考题:

看下面的算式:

(□□□□-□□□□)*□□=900

其中的小方块代表 0~9 的数字,这10个方块刚好包含了 0 ~ 9 中的所有数字。
注意:0不能作为某个数字的首位

小明经过几天的努力,终于做出了答案!如下:
(5012-4987)*36=900

用计算机搜索后,发现还有另外一个解,本题的任务就是:请你算出这另外的一个解。

注意:提交的格式需要与示例严格一致;
括号及运算符号不要用中文输入法;
整个算式中不能包含空格。
.

很多人看到这种类型的题目,第一想法就是暴力破解,实则没必要,但是暴力破解快乐啊! 哈哈哈,看看下面的这个代码,你还快乐吗?
代码太长我直接贴图了:
在这里插入图片描述
看到这个代码你真的很快乐吗? 哈哈哈 ~ 其实我非常的痛苦,感觉脑子快要裂开了 (>_<) . . .

下面我们用 DFS 来解决一下这个题目,代码如下:

#include <iostream>
using namespace std;

size_t flag[10];  // 标记 10 个数字是否被使用过
size_t arr[10];	  // 存储 10 个满足题目意思的书

void Dfs(int n)	  // 深搜思想
{
    if (n == 10)  // 已经找到 10 个不重复的数	
    {
     	// 判断是否满足题目的意思  == 900
  	if (((arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3]) -
   		(arr[4] * 1000 + arr[5] * 100 + arr[6] * 10 + arr[7])) *
   		(arr[8] * 10 + arr[9]) == 900)
  	{
   	    cout << " ( " << (arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3]) << " - " <<
    		(arr[4] * 1000 + arr[5] * 100 + arr[6] * 10 + arr[7]) << " ) " << " * " <<
    		(arr[8] * 10 + arr[9]) << " = " << 900 << endl;
  	}
	
	return;		// 不要忘记了这个返回
    }
    
    for (size_t i = 0; i < 10; ++i)	// 每一个数都有 10 种可能
    {
        if (i == 0 && (n == 0 || n == 4 || n == 8))	// 个别的数只有 9 种可能  开头没有 0 的情况
   	    continue;
  	
  	if (flag[i] == 0)		// 这个数字当前没有被使用过
  	{
   	    flag[i] = 1;		// 标记为使用过
   	    arr[n] = i;			// 将这个数存入数组之中
   	    Dfs(n + 1);			// 下一个位置的深搜
   	    flag[i] = 0;		// 这个数没有用,取消标记(便于下个位置使用)
      	} 
    }
}

int main()
{
    Dfs(0);
    
    return 0;
}

使用 DFS 是不是非常的方便呢,结果如下所示:
在这里插入图片描述


.

寒假作业

题目:
现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:

□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □

每个方块代表 1 ~ 13 中的某一个数字,但不能重复。

思想过程: 这个题目我们继续使用 DFS来求解,但我们在 DFS的过程中,会对程序进行优化,即数字个数每够一个式子成立时,判断这个式子是否满足题意,比如3 个数字时 判断 + 的那个式子,6 个 数字时判断 - 的那个式子,9 个数字时判断 * 的那个式子,12 个数字时判断 / 的那个式子 . . .

优化过程,参考度娘上的大神 ^ _ ^

.

代码如下所示:

#include <iostream>
using namespace std;

int arr[4][3];
int flag[14];
int sum;

// 判断是否满足式子的要求,优化过程
int JudgeIsNoGoOn(int n)
{
    int x = n / 3;
    
    if (n % 12 == 2)   // n == 2 时,判断第一个式子是否满足条件,下面同理 
    {
  	if (arr[x][0] + arr[x][1] != arr[x][2]) return 0;
    }
    
    else if (n % 12 == 5)
    {
  	if (arr[x][0] - arr[x][1] != arr[x][2]) return 0;
    }
    
    else if (n % 12 == 8)
    {
  	if (arr[x][0] * arr[x][1] != arr[x][2]) return 0;
    }
 
    else if (n % 12 == 11)
    {
  	if (arr[x][2] * arr[x][1] != arr[x][0]) return 0;
  	
  	printf("%d + %d = %d\n", arr[0][0], arr[0][1], arr[0][2]);
  	printf("%d - %d = %d\n", arr[1][0], arr[1][1], arr[1][2]);
  	printf("%d * %d = %d\n", arr[2][0], arr[2][1], arr[2][2]);
  	printf("%d / %d = %d\n\n\n", arr[3][0], arr[3][1], arr[3][2]);
    }
    
    return 1;
}

// 与上面差不多的思想,加个判断而已 . . . 
void dfs(int n)
{
    int x = n / 3, y = n % 3;  // 需要存储的二维数组的索引 
    
    // 到最后一个数字了,判断是否满足题目要求
    if (x == 4) { if (JudgeIsNoGoOn(11) == 1) ++sum; }
    else
    {
  	for (int i = 1; i <= 13; ++i)  // 每一个空位 都有 13 种可能性 
  	{
   	    if (flag[i] == 0)
   	    {
    		flag[i] = 1;
    		arr[x][y] = i;
    		
    		// 每存放一位数字,就判断一次(可以前几个式子就不满足)
    		// 当前的数字不满足条件,标记数组值还原,进行下一次的循环    
    		if (JudgeIsNoGoOn(n) == 0) 
    		{
     		    flag[i] = 0;
     		    continue;
    		}
    		
    		dfs(n + 1);     // 下一位数字继续 
    		flag[i] = 0;
   	    }
  	} 
    }
}

熟悉的使用 DFS 或者 BFS,可以帮我们解决很多的问题,而且也有很大的成就感,哈哈 ~


.

浪子花梦

一个有趣的程序员 ~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章