审题:
本题需要我们找出将n个小猫放在有限重的缆车上运下山所需的最小缆车数
时间复杂度分析:本题的数据量小于等于18,所以我们在做好剪枝的前提下可以使用深度优先搜索解题
思路:
方法一:dfs
搜索策略:将小猫一个个的放入缆车中,有两种放法:
第一种是放到当前已有缆车中,第二种是放到新的缆车中
剪枝策略:
剪枝1:可行性剪枝
我们需要在小猫重量+当前缆车中小猫总重小于等于限重时放入,若不满足就剪枝
剪枝2:最优化剪枝
在我们已经搜索过的放法中,最小缆车数会被放到answer,若answer小于当前的缆车数c,那么说明该条路线已经不用搜索了,最优情况也就是等于answer。
剪枝3:优化搜索顺序
优化1:先从体重较大的小猫开始放入,因为这样可以更快搜索出较小的answer
优化2:先考虑已有的缆车放入,再考虑开新缆车,也是服务于剪枝2的
解题:
#include<iostream> #include<algorithm> using namespace std; const int N = 20; int n, w; int answer = N; int c = 0;//当前车数 int cat[N], s[N];//cat负责记录猫的体重,s记录缆车当前负重
(1)main函数与compare函数
bool compare(int a,int b)//改变比较逻辑为降序 {return a > b; } int main() {//录入数据cin >> n >> w;for (int i = 1; i <= n; i++){cin >> cat[i];}//优化搜索顺序sort(cat + 1, cat + n + 1, compare);dfs(1);//传递猫的索引cout << answer << endl;return 0; }
这里我们进行剪枝3的优化1:先从较重的猫开始放入。
所以我们通过compare函数,自己实现大数据优先的降序sort
(2)dfs
void dfs(int pos) {//剪枝:最优化搜索if (c >= answer){return;}//结束条件if (pos > n){answer = c;return;}//优先搜索不开新车情况for (int i = 1; i <= c; i++){//可行性剪枝if (cat[pos] + s[i] > w){continue;}s[i] += cat[pos];dfs(pos + 1);s[i] -= cat[pos];}//开新车情况c++;s[c] = cat[pos];dfs(pos + 1);s[c] = 0;c--; }
结束条件:之所以可以直接让c给到answer,是因为经过了剪枝最优化搜索的筛选,c一定是小于answer的,否则就被剪掉了
剪枝3:我们优先搜索不开新车的情况,所以把开新车情况放在for循环后,只有当所有旧的缆车都无法承载当前猫的体重时才会进入开新车的情况。
而所有的dfs搜索基本都涉及回退,有的是看情况回退,有的是一定回退,像这里这种搜索情况但是不记录具体方法的就是一定回退,所以我们在dfs出来后要还原数据
P10483 小猫爬山 - 洛谷