## [$AcWing$ $165$ 小猫爬山](https://www.acwing.com/problem/content/167/) ### 一、题目描述 翰翰和达达饲养了 $N$ 只小猫,这天,小猫们要去爬山。 经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<)。 翰翰和达达只好花钱让它们坐索道下山。 索道上的缆车最大承重量为 $W$,而 $N$ 只小猫的重量分别是 $C_1、C_2……C_N$。 当然,每辆缆车上的小猫的重量之和不能超过 $W$。 每租用一辆缆车,翰翰和达达就要付 $1$ 美元,所以他们想知道,**最少** 需要付多少美元才能把这 $N$ 只小猫都运送下山? **输入格式** 第 $1$ 行:包含两个用空格隔开的整数,$N$ 和 $W$。 第 $2..N+1$ 行:每行一个整数,其中第 $i+1$ 行的整数表示第 $i$ 只小猫的重量 $C_i$。 **输出格式** 输出一个整数,表示最少需要多少美元,也就是最少需要多少辆缆车。 **数据范围** $1≤N≤18,1≤Ci≤W≤10^8$ **输入样例**: ```cpp {.line-numbers} 5 1996 1 2 1994 12 29 ``` **输出样例**: ```cpp {.line-numbers} 2 ``` ### 二、实现代码 ```cpp {.line-numbers} #include using namespace std; const int N = 20; int n, m; int w[N]; int sum[N]; int ans = N; void dfs(int u, int len) { // 最优性剪枝 if (len >= ans) return; if (u == n + 1) { //走完 ans = len; //更新答案 return; } for (int i = 0; i < len; i++) if (sum[i] + w[u] <= m) { //能放下的情况 sum[i] += w[u]; //放一下试试 dfs(u + 1, len); //下一只小猫,缆车没有增加 sum[i] -= w[u]; //回溯 } // 新开一辆车 sum[len] += w[u]; dfs(u + 1, len + 1); sum[len] -= w[u]; // 恢复现场 } int main() { cin >> n >> m; for (int i = 1; i <= n; i++) cin >> w[i]; // 优化搜索顺序 21ms // 不加优化搜索顺序 88ms // Q:为什么可以采用这样的优化策略? // A: dfs搜索的顺序很关键,很玄学,本着有矛盾先暴露,将一些分枝尽早结束,提前返回,可以提高搜索效率  sort(w + 1, w + 1 + n, greater()); dfs(1, 0); cout<< ans <