算法题解 跑步问题 -- 暴力解法
跑步问题 - 暴力法
题目
某人准备跑20圈来锻炼自己的身体,他准备分多次(>1)跑完,每次都跑正整数圈,然后休息下再继续跑。 为了有效地提高自己的体能,他决定每次跑的圈数都必须比上次跑的多, 设第一次圈数不能小于0,那么请问他可以有多少种跑完这 20 圈的方案? 输出方案总数,以及每种方案的排序。(比如1,19/ 1,2,17 都是有效方案)
分析
本题用动态规划等方法好做,因为圈数比较小,能够方便使用暴力方案解决;
根据条件:1. 他准备分多次(>1)跑完 2.他决定每次跑的圈数都必须比上次跑的多
;分析得出,答案是一系列递增的正数,是排列组合相关问题; 因此大概就是dfs思路了(需要归纳过才好理解,我刚好分析过两篇,有兴趣可以看看;C++算法题解 - 递归实现排列型枚举 - 递归法 (图文) (递归搜索树) - HJfjfK - 博客园 (cnblogs.com));
规律
画出来才清晰
1 2 3 4 5 = 15, +6=21 (不满足) 1 2 3 4 6 = 16,(不满足) 1 2 3 4 7 = 17,(不满足) 1 2 3 4 8 = 18,(不满足) 1 2 3 4 9 = 19,(不满足) 1 2 3 4 10 = 20(满足) 1 2 3 5 6 = 17, +7>20 (不满足) 1 2 3 5 7 = 18, (不满足) 1 2 3 5 8 = 19, (不满足) 1 2 3 5 9 = 20(满足) ... 2 3 4 5 6 = 20(满足) 2 3 4 6 = 15, +7=22(不满足) 2 3 4 7 = 16, ... 19,(不满足) 20,(不满足)
代码实现
1. 初步框架
细节处理比较粗糙,看看思路即可
## 命名不够专业,凑合凑合 const int N = 20; //要跑20圈 int size = 0; //方案数 dfs(下一次待跑圈数,已跑圈数) ##初步确定dfs递归参数,可以有多种方式,选择自己习惯的 int main() { std::vector<int> v; //映射方式;(或用栈或顺序表模拟栈 放入每次待跑圈数) v.resize(21, 0); //扩容并初始化,或者直接使用定长数组 //第一步的圈数,范围1到20圈 for (int i = 1; i <= N; i++) { dfs(i, 0, v); } std::cout<<"总方案数: "<<size << std::endl; return 0; }
2. dfs
- 找递归出口,分别是不满足返回,和满足打印并返回
- 递归遍历(排列组合常用方案)
- 数组记录; 细节:注意要回溯
- 边界优化,时间足够的情况下,可以找规律分析分析;时间紧的时候,紧张不好想就直接干了
//dfs(下一次待跑圈数,已跑圈数) void dfs(int cnt, int ans, std::vector<int>& v) { if (ans + cnt > 20) // { 出口 } if (ans + cnt == 20) { 出口 } v[cnt] = 1; //可以跑 for (int i = cnt+1; i < N-ans; i++) //在上一段规律细心分析可以发现,小于上一次的就不需要再遍历了,然后继续画下图分析规律,结果只需要遍历大于上一次,小于20的即可; /* i<N-ans,规律 (more) (next) [1 -- 19 =20-1] -> [1,2 -- 17=20-3] [1,2,3 -- 14=20-6] 即 ans(已跑圈数) <--> N-ans(要跑圈数) 2 -- 18 3 -- 17 ... */ { dfs(i, ans+cnt, v); //下一次执行(待跑圈数,已跑圈数); } v[cnt] = 0; //回溯 }
3. 补全
#include<iostream> #include<vector> const int N = 20; //要跑20圈 int size = 0; //方案数 void Print(const std::vector<int>& v) { for (int i = 1 ; i<v.size();i++) { if (v[i] == 1) std::cout << i << " " ; } std::cout<<std::endl; } //dfs(下一次待跑圈数,已跑圈数) void dfs(int cnt, int ans, std::vector<int>& v) { if (ans + cnt > 20) // { return ; } if (ans + cnt == 20) { v[cnt] = 1; Print(v); v[cnt] = 0; //回溯 size++; return ; } v[cnt] = 1; //可以跑 for (int i = cnt+1; i < N-ans; i++) /* i<N-ans,规律 (more) (next) 1 -- 19 1,2 -- 17 1,2,3 -- 14 即 ans(已跑圈数) <--> N-ans(要跑圈数) 2 -- 18 3 -- 17 ... */ { dfs(i, ans+cnt, v); //下一次执行(待跑圈数,已跑圈数); } v[cnt] = 0; //回溯 } int main() { std::vector<int> v; //映射方式;(或用栈或顺序表模拟栈) v.resize(21, 0); //第一步的圈数,范围1到20圈 for (int i = 1; i <= N; i++) { dfs(i, 0, v); } std::cout<<"总方案数: "<<size << std::endl; return 0; }
结果打印
本文来自博客园,作者:HJfjfK,原文链接:https://www.cnblogs.com/DSCL-ing/p/18448989
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库