P1149 [NOIP2008 提高组] 火柴棒等式

[NOIP2008 提高组] 火柴棒等式

题目描述

给你 \(n\) 根火柴棍,你可以拼出多少个形如 \(A+B=C\) 的等式?等式中的 \(A\)\(B\)\(C\) 是用火柴棍拼出的整数(若该数非零,则最高位不能是 \(0\))。用火柴棍拼数字 \(0\sim9\) 的拼法如图所示:

注意:

  1. 加号与等号各自需要两根火柴棍;
  2. 如果 \(A\neq B\),则 \(A+B=C\)\(B+A=C\) 视为不同的等式(\(A,B,C\geq0\));
  3. \(n\) 根火柴棍必须全部用上。

输入格式

一个整数 \(n(1 \leq n\leq 24)\)

输出格式

一个整数,能拼成的不同等式的数目。

样例 #1

样例输入 #1

14

样例输出 #1

2

样例 #2

样例输入 #2

18

样例输出 #2

9

提示

【输入输出样例 1 解释】

\(2\) 个等式为 \(0+1=1\)\(1+0=1\)

【输入输出样例 2 解释】

\(9\) 个等式为

\(0+4=4\)\(0+11=11\)\(1+10=11\)\(2+2=4\)\(2+7=9\)\(4+0=4\)\(7+2=9\)\(10+1=11\)\(11+0=11\)

noip2008 提高第二题

2.题解

2.1 错误思路:子集枚举

思路

思路错误在只考虑到了每个数位数都是1的情况,然后利用子集枚举选取两个(有重复),三个(无重复)的情况分别进行讨论,若满足条件ans++
但是对于可能存在的两位数情况,过于繁多,无法进行有效讨论,最后废弃

代码

#include <iostream>
using namespace std;

// 定义每个数字所需的火柴棍数量
int matchsticks[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};

// 函数用于计算数字num所需的火柴棍数量
int countMatchsticks(int num) {
    if (num == 0) return matchsticks[0];
    int count = 0;
    while (num > 0) {
        count += matchsticks[num % 10];
        num /= 10;
    }
    return count;
}

int main() {
    int n;
    cin >> n;

    int totalMatches = 0;
    // 统计总共拥有的火柴棍数量
    for (int i = 0; i <= 1000; ++i) {
        totalMatches += countMatchsticks(i);
    }

    int count = 0;
    // 枚举所有可能的等式
    for (int i = 0; i <= 1000; ++i) {
        for (int j = 0; j <= 1000; ++j) {
            int k = i + j;
            // 如果三个数所需的火柴棍数量之和等于n减去加号和等号的火柴棍数量
            if (countMatchsticks(i) + countMatchsticks(j) + countMatchsticks(k) == n - 4) {
                ++count;
            }
        }
    }

    cout << count << endl;

    return 0;
}

2.2 循环枚举

思路

我上面只考虑了[0,9]几个数组成所需的火柴数,我若是能通过题给范围 0 <= n <= 24, 判断出能组成的最大数是多少,通过循环枚举将范围内所有数所需的火柴数记录下里,再进行判断即可。
考虑极端情况:要使一个数最大,那么另一个加数消耗的火柴数肯定越少越好,同时组成的新的和肯定也要消耗火柴越少越好。
除去我们 + 和 = 所需的四个火柴 n - 4 <= 20

// 定义每个数字所需的火柴棍数量
int matchsticks[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
这里我们观察一下,发现数字1消耗的火柴数最少,所以选择的加数为 1(1111可作为加数也可以作为和),而另一个加数经过判断 20 < 1111 + 1 = 1112(21根火柴) < 1110 + 1 = 1111(22根) 均刚好超过了20根火柴,实际上不会有比这消耗更少火柴棒的情况了,所以只需要讨论[0,1111]内的数即可

代码

#include <iostream>
using namespace std;

// 定义每个数字所需的火柴棍数量
int matchsticks[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};

// 函数用于计算数字num所需的火柴棍数量
int countMatchsticks(int num) {
    if (num == 0) return matchsticks[0];
    int count = 0;
    while (num > 0) {
        count += matchsticks[num % 10];
        num /= 10;
    }
    return count;
}

int main() {
    int n;
    cin >> n;

    int totalMatches = 0;
    // 统计总共拥有的火柴棍数量
    for (int i = 0; i <= 1111; ++i) {
        totalMatches += countMatchsticks(i);
    }

    int count = 0;
    // 枚举所有可能的等式
    for (int i = 0; i <= 1111; ++i) {
        for (int j = 0; j <= 1111; ++j) {
            int k = i + j;
            // 如果三个数所需的火柴棍数量之和等于n减去加号和等号的火柴棍数量
            if (countMatchsticks(i) + countMatchsticks(j) + countMatchsticks(k) == n - 4) {
                ++count;
            }
        }
    }

    cout << count << endl;

    return 0;
}

posted @ 2024-02-18 16:09  DawnTraveler  阅读(87)  评论(0编辑  收藏  举报