使用DFS求解“24点游戏算法”
1.题目
问题描述:
给出4个1-10的数字,通过加减乘除,得到数字为24就算胜利
输入:
4个1-10的数字。[数字允许重复,但每个数字仅允许使用一次,测试用例保证无异常数字]
输出:
true or false
示例:
输入:
7 2 1 10
输出
true
2.思路精要:
- (1)依次选择n[0],n[1],n[2],n[3]作为顶点。
- (2)某次遍历后,如果最后节点的值为24则返回true,否则回溯。
- (3)所有遍历后均得不到24,返回false。
3. 该题的图到底长什么样呢?
经过分析,如下图所示:
注意;图中的标注为各个顶点的初始值,遍历过程中顶点的值会发生变化。如按加法且路径为左上角-->右上角-->右下角-->左下角,则左下角顶点的值为n[0]+n[1]+n[2]+n[3]。因此,一次遍历后,最后节点的值等于24,就意味着可以得到24。
4.具体代码
// package org.jzy.huawei108;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
// 初始化数字数组和标志数组
int[] nums = new int[4];
int[] signs = new int[4];
for (int i = 0; i < nums.length; i++) {
nums[i] = scanner.nextInt();
}
boolean can = false; // 是否能得到24
for (int i = 0; i < nums.length; i++) {
signs[i] = 1;
if (dfs(nums, signs, nums[i], 24)) {
can = true;
break;
}
signs[i] = 0;
}
System.out.println(can);// 输出结果
}
}
/**
* 深度优先算法逻辑
*
* @param nums 输入的4个数字
* @param signs 访问标志数组
* @param v 顶点的值
* @param required 需要通过四则运算得到的数字
* @return
*/
private static boolean dfs(int[] nums, int[] signs, int v, int required) {
boolean allVisited = true;// 四个角均被访问
for (int sign : signs) {
if (sign == 0) {
allVisited = false;
}
}
if (allVisited) {
return v == required; // 在所有节点均被访问的前提下,判断最后的结果是否为所需要的结果。
}
// 访问所有的邻接顶点
for (int i = 0; i < nums.length; i++) {
if (signs[i] == 0) {
signs[i] = 1;
if (dfs(nums, signs, v + nums[i], required) // 加法
|| dfs(nums, signs, v - nums[i], required) // 减法
|| dfs(nums, signs, v * nums[i], required) // 乘法
|| nums[i] != 0 && v % nums[i] == 0 && dfs(nums, signs, v / nums[i], required)/* 除法 */) {
return true;// 如果可以通过四则运算得到需要的结果,则返回true。
}
signs[i] = 0; // 如果不能通过四则运算得到,则进行回溯。
}
}
return false;//当所有情况均得不到需要的结果,返回false。
}
}
京公网安备 11010502036488号