回溯DFS

回溯DFS

算法概论第十四周

679. 24 Game

679. 24 Game——链接

题目描述

You have 4 cards each containing a number from 1 to 9. You need to judge whether they could operated through *, /, +, -, (, ) to get the value of 24.

Example 1:
Input: [4, 1, 8, 7]
Output: True
Explanation: (8-4) * (7-1) = 24
Example 2:
Input: [1, 2, 1, 2]
Output: False
Note:
The division operator / represents real division, not integer division. For example, 4 / (1 - 2/3) = 12.
Every operation done is between two numbers. In particular, we cannot use - as a unary operator. For example, with [1, 1, 1, 1] as input, the expression -1 - 1 - 1 - 1 is not allowed.
You cannot concatenate numbers together. For example, if the input is [1, 2, 1, 2], we cannot write this as 12 + 12.

实现代码

class Solution {
    public boolean judgePoint24(int[] nums) {
        ArrayList A = new ArrayList<Double>();
        for (int v: nums) A.add((double) v);
        return solve(A);
    }
    private boolean solve(ArrayList<Double> nums) {
        if (nums.size() == 0) return false;
        if (nums.size() == 1) return Math.abs(nums.get(0) - 24) < 1e-6;

        for (int i = 0; i < nums.size(); i++) {
            for (int j = 0; j < nums.size(); j++) {
                if (i != j) {
                    ArrayList<Double> nums2 = new ArrayList<Double>();
                    for (int k = 0; k < nums.size(); k++) if (k != i && k != j) {
                        nums2.add(nums.get(k));
                    }
                    for (int k = 0; k < 4; k++) {
                        if (k < 2 && j > i) continue;
                        if (k == 0) nums2.add(nums.get(i) + nums.get(j));
                        if (k == 1) nums2.add(nums.get(i) * nums.get(j));
                        if (k == 2) nums2.add(nums.get(i) - nums.get(j));
                        if (k == 3) {
                            if (nums.get(j) != 0) {
                                nums2.add(nums.get(i) / nums.get(j));
                            } else {
                                continue;
                            }
                        }
                        if (solve(nums2)) return true;
                        nums2.remove(nums2.size() - 1);
                    }
                }
            }
        }
        return false;
    }
}
<think>好的,我现在需要帮助用户理解并实现DFS回溯算法。用户已经提供了一些参考资料,我需要结合这些资料来组织回答。首先,我需要明确DFS回溯的区别,根据引用[2],回溯法属于DFS的一种,但主要区别在于回溯会剪枝,并且需要保存和恢复状态。然后,用户可能想知道如何具体实现,比如代码结构和关键步骤。根据引用[4]和[5],DFS回溯通常用递归实现,需要处理递归终止条件和状态标记回溯。 接下来,我需要将原理部分讲清楚,比如递归终止条件、选择路径、标记回溯、状态恢复这些步骤。然后给出一个示例代码,比如全排列问题,这是经典的DFS回溯案例,引用[4]中的C++代码可以转换成Python示例。同时要注意代码中的注释,解释关键点,比如递归调用后的book[i]=0就是状态恢复。 然后,对比DFS回溯的区别,引用[2]提到回溯需要剪枝和状态管理,这里需要强调回溯法的优化特性。最后生成相关问题,确保覆盖用户可能感兴趣的扩展方向,比如剪枝方法、与BFS的区别、应用场景等。 需要确保回答结构清晰,分步骤讲解,并且引用正确的参考资料。同时,按照用户要求使用中文,数学公式用$...$,独立公式用$$...$$,但在这个问题中可能数学内容不多,所以可能不需要太多公式。检查是否有需要加引用标识的地方,比如在提到回溯DFS区别时引用[2],在代码示例参考引用[4]和[5]。</think>### 深度优先搜索(DFS回溯算法实现与原理 #### 一、DFS回溯算法核心原理 1. **递归终止条件** 当搜索路径满足目标要求(例如找到解或遍历完所有可能)时终止递归,例如全排列问题中路径长度等于元素个数时输出结果[^4]。 2. **选择与路径探索** 通过循环遍历所有可能的候选选项(如未使用的数字、相邻节点),尝试将其加入当前路径。例如: $$ \text{for } i \text{ in } [1,n] \rightarrow \text{选择未使用的 }i \text{ 加入路径} $$ 3. **标记回溯** 在尝试候选选项时标记已使用状态(如`book[i]=1`),递归结束后撤销标记(`book[i]=0`)以恢复状态,这是回溯的核心操作[^5]。 4. **剪枝优化(回溯法的关键)** 通过提前终止无效路径(如检测到当前路径不可能满足条件)减少搜索空间,例如数独游戏中提前排除重复数字的分支[^2]。 --- #### 二、DFS回溯算法实现(Python示例:全排列问题) ```python def dfs_backtrack(n, path, used, result): # 终止条件:路径长度等于n时记录结果 if len(path) == n: result.append(path.copy()) return # 遍历候选选项 for i in range(1, n+1): if not used[i]: # 标记选择 used[i] = True path.append(i) # 递归探索下一层 dfs_backtrack(n, path, used, result) # 回溯:撤销标记并移除路径 used[i] = False path.pop() # 调用示例 n = 3 result = [] dfs_backtrack(n, [], [False]*(n+1), result) print("全排列结果:", result) ``` **关键注释** - `used`数组标记数字是否被使用 - `path.pop()`和`used[i]=False`实现状态回溯[^4] --- #### 三、DFS回溯的关系 | 特性 | 标准DFS | 回溯法 | |--------------------|----------------------|----------------------| | **目标** | 遍历所有节点/路径 | 找到特定解并优化搜索 | | **状态管理** | 通常无状态恢复 | 必须恢复状态(回溯) | | **剪枝** | 无 | 通过条件提前终止分支 | | **应用场景** | 连通性检测、拓扑排序 | 排列组合、迷宫问题 | --- #### 四、典型应用场景 1. **组合问题**:如子集生成($C(n,k)$) 2. **排列问题**:如全排列($n!$种可能) 3. **棋盘类问题**:N皇后、数独求解 4. **路径搜索**:迷宫最短路径(需结合剪枝) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值