DFS 等式问题

回溯算法建立在DFS基础之上的,但不同的是在搜索过程中,达到结束条件后,恢复状态,回溯上一层,再次搜索

当问题需要"回头",以此来查找出所有的解的时候,使用回溯算法。
即满足结束条件或者发现不是正确路径的时候(走不通),要撤销选择,回退到上一个状态,继续尝试,直到找出所有解为止

回溯算法模板
void dfs()//参数用来表示状态  
{  
    if(到达终点状态)  
    {  
        ...//根据题意添加  
        return;  
    }  
    if(越界或者是不合法状态)  
        return;  
    if(特殊状态)//剪枝
        return ;
    for(扩展方式)  
    {  
        if(扩展方式所达到状态合法)  
        {  
            修改操作;//根据题意来添加  
            标记;  
            dfs();  
            (还原标记);  
            //是否还原标记根据题意  
            //如果加上(还原标记)就是 回溯法  
        }  
    }  
}

任何大于1的自然数n,都可以拆分为若干小于n的自然数之和。
const int MAXN = 10 + 2;
int path[MAXN] = { 1 };
void dfs_equation1(int s, int n, int bits, int& sum)
{
    for (int i = path[bits - 1]; i <= s; ++i)   // 确保path[] 升序,有[path[bits - 1], s]中可能
    {
        if (i < n)
        {
            path[bits] = i;
            s -= i;
            if (s == 0)
            {
                ++sum;
                for (int j = 1; j <= bits; ++j)
                    std::cout << path[j] << " ";
                std::cout << std::endl;
            }
            else if (s > 0)
            {
                dfs_equation1(s, n, bits + 1, sum);
            }
            s += i;  //回溯还原相关状态
        }
    }
}

void dfs_equation1_1(int s, int n, int bits, int& sum)
{
    if (s == 0)
    {
        ++sum;
        for (int j = 1; j < bits; ++j)
            std::cout << path[j] << " ";
        std::cout << std::endl;
    }

    for (int i = path[bits - 1]; i <= s; ++i)   // 确保path[] 升序,有[path[bits - 1], s]中可能
    {
        if (i < n)
        {
            path[bits] = i;
            dfs_equation1_1(s-i, n, bits + 1, sum);  // s-i 放在参数中,不需要手动回溯还原相关状态
        }
    }
}

int main()
{
    int sum = 0;
    dfs_equation1(4, 4, 1, sum);
    std::cout << sum << std::endl;
    sum = 0;
    dfs_equation1_1(4, 4, 1, sum);
    std::cout << sum << std::endl;

    return 0;
}

1 1 1 1
1 1 2
1 3
2 2
4
1 1 1 1
1 1 2
1 3
2 2
4


在1到9之间插入“+”或“-”或者不插入任何符号,
使等式1 2 3 4 5 6 7 8 9 = 108成立

#include <iostream>
#include <vector>

const int MAXN = 10 + 2;
int sign[MAXN] = { 0 };

int calc()
{
    int tmp = 0, sum = 1, i = 1, j = 0;
    bool flag = true;
    std::vector<int> vec;
    vec.push_back(1);
    for (i = 1; i <= 8; ++i)
        if (sign[i] == 0)
            vec[vec.size() - 1] = vec[vec.size() - 1] * 10 + (i + 1);
        else
            vec.push_back(i + 1);
    i = 1;
    j = 0;
    sum = vec[j];
    while (i <= 8)
    {
        if (sign[i] == 1)
            sum += vec[++j];
        else if (sign[i] == 2)
            sum -= vec[++j];

        ++i;
    }

    return sum;
}

void dfs_equation2(int layers, int res, int& total)
{
    if (layers > 8)
    {
        int sum = calc();
        if (res == sum)
        {
            ++total;
            std::cout << 1;
            int tmp = 1;
            for (int i = 1; i <= 8; ++i)
            {
                if (sign[i] == 1)
                    std::cout << "+";
                else if (sign[i] == 2)
                    std::cout << "-";
                std::cout << (i + 1);
            }
            std::cout << "=" << sum << std::endl;
        }

        return;
    }

    for (int i = 0; i < 3; ++i)   // 0:null, 1:+, 2:-
    {
        sign[layers] = i;
        dfs_equation2(layers + 1, res, total);
    }
}

int main()
{
    int res = 108;
    int total = 0;
    dfs_equation2(1, res, total);
    std::cout << total << std::endl;

    return 0;
}

123+4-5-6-7+8-9
123-45+6+7+8+9
123-4+5-6+7-8-9
12+34+56+7+8-9
12+3+4+5+67+8+9
12+3-4-5+6+7+89
12-3+4+5-6+7+89
1+23+4+56+7+8+9
1+23+4+5+6+78-9
1+23-4-5+6+78+9
1+2+34+5+67+8-9
1+2+34-5-6-7+89
1+2+3+4+5+6+78+9
1+2-3+45-6+78-9
1-2-34+56+78+9
15
 

### 关于2016年DFS算法解决凑算式问题的解题思路 #### 解题背景 题目要求使用四个不同的数字组成一个乘法算式,其乘积仍由这四个数字构成。此问题可以通过深度优先搜索(DFS)来枚举所有可能的情况,并验证每种组合是否符合条件。 #### 数据处理与优化策略 由于浮点数运算可能存在精度误差,因此可以将分数运算转化为整数运算以提高准确性[^1]。具体而言,在计算过程中应避免直接比较浮点数值,而是通过调整表达式的结构使其仅涉及整数操作。 #### DFS实现逻辑 利用递归来实现深度优先搜索是一种常见且有效的方式。对于此类问题,可以从最高位开始逐位尝试填充未使用的数字直到完成整个数列构建为止;每次递归调用前需记录当前状态以便回溯时恢复原状[^4]。 以下是基于上述原理编写的一个Python版本程序示例: ```python from itertools import permutations def check_formula(a, b, c): """验证给定三个参数a,b,c组成的等式是否成立""" return a * b == c count = 0 digits_set = set(range(10)) for perm in permutations(digits_set, 4): num_list = list(map(int, ''.join(map(str,perm)))) # 枚举两个因子位置关系 for split_point in range(1,3): factor_one = int(''.join(map(str,num_list[:split_point]))) remaining_numbers = num_list[split_point:] product_candidate = [] for second_split in range(1,len(remaining_numbers)): factor_two = int(''.join(map(str,[remaining_numbers[i] for i in range(second_split)]))) possible_product_digits = sorted([d for d in str(factor_one*factor_two)]) original_permutation_sorted =sorted(num_list) if possible_product_digits==original_permutation_sorted and not any(x.startswith('0') for x in map(str,(factor_one,factor_two))): count +=1 print(count//2) # 考虑到交换律重复计数情况除以二得到最终答案数量 ``` 该脚本首先定义了一个辅助函数`check_formula()`用于检测特定三元组形成的方程是否合法。接着运用标准库中的permutations工具生成候选排列集合,并针对每一个实例执行必要的拆分测试以及零前置过滤器应用过程。最后输出结果考虑到乘法规则下的互换性质进行了适当修正。 #### 总结 综上所述,采用DFS方法配合合理的剪枝条件能够高效地求解这类约束条件下产生的特殊数学模式识别类问题。通过对原始数据集的有效划分和逐步深入探索潜在匹配项,可以在合理时间内得出预期解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值