2019年第十届蓝桥杯 C++省赛B组 第四题: 数的分解

2019年第十届蓝桥杯 C++省赛B组 第四题: 数的分解

D: 数的分解(本题总分:10 分)

【问题描述】
把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包
含数字 2 和 4,一共有多少种不同的分解方法?
注意交换 3 个整数的顺序被视为同一种方法,例如 1000+1001+18 和
1001+1000+18 被视为同一种。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

解题

这道题是一个暴力破解题,可以采用三重循环的思路来进行列举后,对三个数据进行判断,是否符合要求。但是对于是否重复的问题不好解决。
我们可以将三个数分别按照小,中,大来列举,这样就能保证最小的数一定出现在第一个位置,最大的数一定出现在第三个的位置,这样就能避免重复的分解方法。代码如下:

#include <iostream>
using namespace std ;
bool contain(int n){
    int t ;
    while(n){
        t = n % 10 ;
        if(t == 2 || t == 4)
            return true ;
        else
            n /= 10 ;
    }
    return false ;
}
bool break_down(int i , int j , int k){
    if(contain(i) || contain(j) || contain(k))
        return false ;
    else
        return true ;
}
int main(){
    int num = 0 ;
    for(int i = 1 ; i < 2019 ; ++ i)
        for(int j = i + 1 ; j < 2019 ; ++ j)
            for(int k = j + 1 ; k < 2019 ; ++ k)
                if(break_down(i , j , k) && i + j + k == 2019)
                    num ++ ;
    printf("%d\n" , num) ;
    return 0 ;
}

问题解决了但是循环次数太多了,因为我们的遍历区间取得太大了。事实上,对于I而言,它是三个数中最小的,因此它不可能超过672,当I = 672时,j 只能为673,k只能为674。如果I再大一点,就无法满足i < j < k且i + j + k == 2019了。同理可得 j 不可能超过 1008 ,而k不可能超过2019 - j 。所以可以缩小i , j , k 的循环区间 ;

#include <iostream>
using namespace std ;
bool contain(int n){
    int t ;
    while(n){
        t = n % 10 ;
        if(t == 2 || t == 4)
            return true ;
        else
            n /= 10 ;
    }
    return false ;
}
bool break_down(int i , int j , int k){
    if(contain(i) || contain(j) || contain(k))
        return false ;
    else
        return true ;
}
int main(){
    int num = 0 ;
    for(int i = 1 ; i < 673 ; ++ i)
        for(int j = i + 1 ; j < 1009 ; ++ j)
            for(int k = j + 1 ; k < 2019 - j ; ++ k)
                if(break_down(i , j , k) && i + j + k == 2019)
                    num ++ ;
    printf("%d\n" , num) ;
    return 0 ;
}

结果

40785

猜你喜欢

转载自blog.csdn.net/just_gong/article/details/106662090