acwing 165.小猫爬山

题目

原题链接 165.小猫爬山

翰翰和达达饲养了 N 只小猫,这天,小猫们要去爬山。
经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<)。翰翰和达达只好花钱让它们坐索道下山。
索道上的缆车最大承重量为 W,而 N 只小猫的重量分别是 C1、C2……CN。
当然,每辆缆车上的小猫的重量之和不能超过 W。
每租用一辆缆车,翰翰和达达就要付 1美元,所以他们想知道,最少需要付多少美元才能把这 N只小猫都运送下山?

输入格式

第 1行:包含两个用空格隔开的整数,N和 W。
第 2…N+1 行:每行一个整数,其中第 i+1行的整数表示第 i只小猫的重量 Ci。

输出格式

输出一个整数,表示最少需要多少美元,也就是最少需要多少辆缆车。

数据范围:

1≤N≤18
1≤Ci≤W≤10^8

输入样例:

5 1996
1
2
1994
12
29

输出样例:

2

思路:

1.用数组a存入n只小猫占的容量,数组c表示第i个缆车的剩余容量,初始化为w。
2.暴力dfs。递归每层dfs,传入两个参数u和cnt,u表示递归到第u只小猫,cnt表示已经用了几辆缆车。递归最深处,即u > n,return返回上一层dfs。
每层dfs处理过程:for(1 ~ cnt) 遍历已经使用的缆车,看能不能装下该层小猫,如果能继续dfs(u+1,cnt)。如果这cnt辆缆车都不能装入该层小猫,则新开一辆缆车,递归进入下一层。记住:递归结束要回溯,恢复递归调用前的数据或标记。
3.暴力dfs会TLE。思考如何优化:
1)最优性剪枝。当递归到某层时,cnt>ans(ans 已经存储了一次结果), 就没有必要继续dfs下去了,直接return 返回上一层dfs
2)优化搜索顺序。优先搜索分支较小的节点。因此我们可以预先把a数组从大到小排序。每次递归取的小猫重量是尽可能大的。

代码:

#include<bits/stdc++.h>
using namespace std;

const int MAX_N = 20; // 小猫最多18只
int a[MAX_N]; //ai 表示第i只小猫占的容量大小
int c[MAX_N];// ci 表示第i个缆车剩余容量,初始化容量都为w
int ans = 1e3;// 将初始答案给最大,防止if(cnt>ans)运行了,而if(u>n)ans = cnt; ans还没有存储结果 
int n, w;

void dfs(int u, int cnt) {
    if (cnt > ans) return; // 最优性剪枝
    if (u > n) {
        ans = cnt;
        return; // 递归返回条件
    }
    for (int i = 1; i <= cnt; i++) {
        if (c[i] - a[u] < 0) continue;
        c[i] -= a[u]; // 尝试放入缆车
        dfs(u + 1, cnt);
        c[i] += a[u]; // 恢复状态,回溯
    }
    // 如果当前小猫单独放入一个新组
  
    c[cnt+1] -= a[u]; // 新开一个组,并放入当前小猫
    dfs(u + 1, cnt + 1);
    c[cnt+1]  += a[u];
}

int main() {
    cin >> n >> w;
    for (int i = 1; i <= n; i++) cin >> a[i],c[i] = w;
    // 初始化c数组,每个位置都等于w,代表缆车的初始容量
    sort(a+1,a+1+n);
    reverse(a+1,a+1+n);//优化搜索顺序,优先搜索分支较少的节点
    dfs(1, 1); // 题目中n最小为1,缆车也至少有1辆
    cout << ans << endl;
    return 0;
}

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值