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