😊😊 😊😊
不求点赞,只求耐心看完,指出您的疑惑和写的不好的地方,谢谢您。本人会及时更正感谢。希望看完后能帮助您理解算法的本质
😊😊 😊😊
一、题目:
=
二、暴力做法:
1、暴力做法!直接一个一个枚举判断!
#include<stdio.h>
int sum; // 求和!
int main ()
{
int i, j;
for (i=3; i < 1000; i ++)
{
if (i % 3 == 0 || i % 5 == 0)
{
sum += i;
}
}
printf ("%d", sum);
return 0;
}
三、递归:
递归求解的思路可以考虑将问题拆分为两个子问题:
求小于n的自然数中所有3的倍数之和。
求小于n的自然数中所有5的倍数之和。
最终结果为这两个子问题的和。
为了避免重复计算(15,45....会重复累计!!
),可以使用递归函数来处理这两个子问题。
#include <iostream>
using namespace std;
int sum(int n) {
if (n <= 0) {
return 0;
}
int cur = n - 1;
if (cur % 3 == 0 || cur % 5 == 0) {
return cur + sum(cur);
} else {
return sum(cur);
}
}
int main() {
cout << sum(1000) << endl; // 输出233168
return 0;
}
四、求和公式:等差数列
首先,我们可以得到所有小于 n n n 的 3 3 3 的倍数的和为 3 + 6 + 9 + . . . + 3 × ⌊ n − 1 3 ⌋ 3+6+9+...+3\times \lfloor\frac{n-1}{3}\rfloor 3+6+9+...+3×⌊3n−1⌋,这个和可以用等差数列求和公式求出: ( 3 + ⌊ n − 1 3 ⌋ × 3 ) × ⌊ n − 1 3 ⌋ 2 \frac{(3+\lfloor\frac{n-1}{3}\rfloor \times 3) \times \lfloor\frac{n-1}{3}\rfloor}{2} 2(3+⌊3n−1⌋×3)×⌊3n−1⌋。
同样地,我们可以得到所有小于 n n n 的 5 5 5 的倍数的和为 5 + 10 + 15 + . . . + 5 × ⌊ n − 1 5 ⌋ 5+10+15+...+5\times \lfloor\frac{n-1}{5}\rfloor 5+10+15+...+5×⌊5n−1⌋,这个和可以用等差数列求和公式求出: ( 5 + ⌊ n − 1 5 ⌋ × 5 ) × ⌊ n − 1 5 ⌋ 2 \frac{(5+\lfloor\frac{n-1}{5}\rfloor \times 5) \times \lfloor\frac{n-1}{5}\rfloor}{2} 2(5+⌊5n−1⌋×5)×⌊5n−1⌋。
但是,由于上述两个求和公式中都有一个 ⌊ n − 1 x ⌋ \lfloor\frac{n-1}{x}\rfloor ⌊xn−1⌋,其中 x x x 可能是 3 3 3 或 5 5 5,我们需要避免重复计算。因此,我们可以再加上所有小于 n n n 的 15 15 15 的倍数的和,即 15 + 30 + 45 + . . . + 15 × ⌊ n − 1 15 ⌋ 15+30+45+...+15\times \lfloor\frac{n-1}{15}\rfloor 15+30+45+...+15×⌊15n−1⌋。但是注意到 15 15 15 的倍数在计算 3 3 3 的倍数和 5 5 5 的倍数时已经被算过了,所以需要将这部分和减去。
综上,小于 n n n 的所有 3 3 3 或 5 5 5 的倍数之和为: ( 3 + ⌊ n − 1 3 ⌋ × 3 ) × ⌊ n − 1 3 ⌋ 2 + ( 5 + ⌊ n − 1 5 ⌋ × 5 ) × ⌊ n − 1 5 ⌋ 2 − ( 15 + ⌊ n − 1 15 ⌋ × 15 ) × ⌊ n − 1 15 ⌋ 2 \frac{(3+\lfloor\frac{n-1}{3}\rfloor \times 3) \times \lfloor\frac{n-1}{3}\rfloor}{2}+\frac{(5+\lfloor\frac{n-1}{5}\rfloor \times 5) \times \lfloor\frac{n-1}{5}\rfloor}{2}-\frac{(15+\lfloor\frac{n-1}{15}\rfloor \times 15) \times \lfloor\frac{n-1}{15}\rfloor}{2} 2(3+⌊3n−1⌋×3)×⌊3n−1⌋+2(5+⌊5n−1⌋×5)×⌊5n−1⌋−2(15+⌊15n−1⌋×15)×⌊15n−1⌋。
代码如下:
#include <iostream>
using namespace std;
int main() {
int n = 1000;
int sum = 0;
// 计算3的倍数之和
int m3 = (n - 1) / 3;
sum += 3 * m3 * (m3 + 1) / 2;
// 计算5的倍数之和
int m5 = (n - 1) / 5;
sum += 5 * m5 * (m5 + 1) / 2;
// 排除重复计算的15的倍数之和
int m15 = (n - 1) / 15;
sum -= 15 * m15 * (m15 + 1) / 2;
cout << sum << endl;
return 0;
}
草稿:
//233168;
//266333:表明有存在重复的计算:如:15, 45, 75...都是3和5的倍数,由于3和5的倍数是分开计算的,
//所以说最后造成了累加两次!
//没有考虑重复累加计算的递归代码:
#include<iostream>
using namespace std;
int sum;
void dfs(int m3, int m5) //两个参数分别依次表示3的倍数,5的倍数!
{
if (m3 >= 10 && m5 >= 10) //递归的出口!
return ; //搜索结束!
if (m3 < 10) sum += m3;
if (m5 < 10) sum += m5;
dfs (m3 + 3, m5 + 5); //逐步累加!
}
int main()
{
dfs(3, 5); //递归从3和5的一倍开始!
cout << sum << endl;
return 0;
}
#include<stdio.h>
int sum; // 求和!
int main ()
{
int i, j;
for (i=3; i < 10; i ++)
{
if (i % 3 == 0 || i % 5 == 0)
{
sum += i;
}
}
printf ("%d", sum);
return 0;
}
//数学公式:
#include<iostream>
using namespace std;
int main()
{
cout << 333*(3+999)/2 + 199*(1000)/2 << endl;
return 0;
}