P1149 [NOIP2008 提高组] 火柴棒等式 - 高效枚举解法

🌟 P1149 [NOIP2008 提高组] 火柴棒等式 - 高效枚举解法

解题思路

寻找所有满足 A + B = C 的火柴棒等式,其中 ABC 是用火柴棒拼成的整数。通过预处理每个数字的火柴棒数量,枚举可能的 AB,验证总火柴棒数量是否匹配。


核心算法步骤

1. 预处理数字火柴棒数量

  • 基础数字:0-9 的火柴棒数量预先存储
  • 扩展计算:预处理 0 到 2400 所有整数的火柴棒数量

2. 枚举所有可能的 A 和 B

  • 枚举范围0 ≤ A, B ≤ 1200(覆盖题目所有可能情况)
  • 计算 CC = A + B
  • 验证条件ABC 的火柴棒总数等于 n-4(加号和等号各需 2 根)

代码实现

#include <iostream>
#include <vector>
using namespace std;

int main() {
    // 每个数字0-9所需的火柴棒数量
    vector<int> digit_cost = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
    
    // 预处理0-2400所有数字的火柴棒数量
    vector<int> num_cost(2401, 0);
    for (int i = 0; i <= 2400; i++) {
        if (i == 0) {
            num_cost[0] = digit_cost[0];
        } else {
            int n = i;
            while (n > 0) {
                num_cost[i] += digit_cost[n % 10];
                n /= 10;
            }
        }
    }

    int n;
    cin >> n;
    int total_eq = 0;

    // 枚举所有可能的A和B(0-1200)
    for (int A = 0; A <= 1200; A++) {
        for (int B = 0; B <= 1200; B++) {
            int C = A + B;
            if (C > 2400) continue; // 超出预处理范围则跳过
            if (num_cost[A] + num_cost[B] + num_cost[C] == n - 4) {
                total_eq++;
            }
        }
    }

    cout << total_eq << endl;
    return 0;
}

算法优化点

  1. 预处理优化

    • 预先计算所有可能数字的火柴棒数量,避免重复计算
    • 快速查询:O(1) 时间获取任意数字的火柴棒数量
  2. 枚举范围优化

    • 合理设定 AB 的上限为 1200,覆盖 n ≤ 24 的所有情况
    • 跳过 C > 2400 的无效组合
  3. 内存管理

    • 使用 vector 存储预处理结果,空间复杂度 O(2401)

复杂度分析

维度分析说明
时间复杂度O(K²),K=1201,约 1.44e6 次操作
空间复杂度O(M),M=2401,约 10KB 内存

算法演示

样例 1:n=14

  • 有效等式0+1=11+0=1
  • 计算过程
    A=0, B=1 → C=1 → 6+2+2=10 → 10+4=14 ✔
    A=1, B=0 → C=1 → 2+6+2=10 → 10+4=14 ✔
    
  • 输出:2

样例 2:n=18

  • 有效等式:9 个(如 0+4=41+10=11 等)
  • 输出:9

特殊情况处理

情况处理方式结果
全零等式0+0=0 需 18+4=22 根火柴n=22 时有效
大数组合跳过 C > 2400 的组合不计数
最小 n (n < 4)无解输出 0

算法特点

  • 高效性:预处理 + 枚举保证 O(1) 查询效率
  • 精确性:覆盖所有可能的等式组合
  • 鲁棒性:正确处理边界值和极端情况
  • 代码简洁:核心逻辑仅 20 行
  • 可扩展性:易调整预处理范围应对更大数据

测试验证:已通过洛谷官方测试,包括全零、单数字等极端场景。


Sanhai AI
### 关于NOIP 2008 火柴等式 #### 题目内容 给定 n 根火柴棍,可以拼出多少个形如 “A + B = C” 的等式?其中 A、B 和 C 是由火柴棍拼成的整数(如果这些数是非零数值,则其最高位不可为零)。具体来说,用火柴棍拼写数字 0 到 9 所需的数量如下表所示: | 数字 | 使用火柴数量 | | --- | --------------| | 0 | 6 | | 1 | 2 | | 2 | 5 | | 3 | 5 | | 4 | 4 | | 5 | 5 | | 6 | 6 | | 7 | 3 | | 8 | 7 | | 9 | 6 | 输入仅有一个正整数 n (n ≤ 24),表示可用的火柴总数。 输出应是一个整数,代表能成的合法等式的数目[^1]。 #### 解题思路 对于这个问题,核心在于枚举所有可能构成的有效合。由于题目规定了最大火柴数不超过24根,因此可以直接通过预处理的方式计算每一个数字所需消耗的火柴量,并基于此构建动态规划模型来进行求解。 为了简化问题复杂度,在实际编程实现过程中通常会采用记忆化搜索的方法来避免重复运算。这种方法能够有效地减少不必要的计算次数,从而提升程序效率。另外需要注意的是,因为涉及到加法操作,所以还需要考虑进位的情况以及如何合理分配剩余的火柴用于表达其他部分的结果。 ```python # Python code snippet to solve the matchstick equation problem. def count_equations(n): # Define a dictionary mapping each digit to its corresponding number of matches required. digits_to_matches = {str(i): v for i, v in enumerate([6, 2, 5, 5, 4, 5, 6, 3, 7, 6])} @functools.lru_cache(None) def dfs(a, b, c, remaining): if remaining < 0: return 0 if not a and not b and not c: return int(remaining == 0) result = 0 max_digit = min(int(bool(a)), int(bool(b)), int(bool(c))) for d in range(max_digit, 10): new_remaining = ( remaining - digits_to_matches[str(d)] * sum((a > 0, b > 0, c > 0)) + ((d >= 5) << bool(a & b)) ) result += dfs( a - (d != 0), b - (d != 0), c - (d != 0 or (not a and not b)), new_remaining, ) return result total_ways = 0 for first_num_len in range(1, n//2+1): for second_num_len in range(1, n-first_num_len+1): third_num_len = n - first_num_len - second_num_len if any(x <= 0 for x in [first_num_len, second_num_len, third_num_len]): continue total_ways += dfs(first_num_len, second_num_len, third_num_len, n-sum(digits_to_matches.values())) return total_ways if __name__ == "__main__": import functools print(count_equations(int(input()))) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值