目录
1.题目描述
题目来源:acwing
翰翰和达达饲养了 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≤1e8
输入样例:
5 1996
1
2
1994
12
29
输出样例:
2
2.题意
题意:将输入的这n只重量不完全相同的小猫,进行组合放进数台负重为W的缆车上,输出所需的最少缆车的租金(一辆缆车的租金为1美元,故等价于输出所需缆车数量)
3.解题思路
通过DFS来解决这道题,首先确定其每一步的状态为已租用的缆车数和进行选择的小猫,每一步的选择1为将该小猫放入已租的缆车,2为将小猫放入新租的缆车。问题边界为,所有的小猫已完成选择。
剪枝1:若发现当前状态已租用的缆车数大于等于已记录的缆车数,则结束当前状态
剪枝2:因为重量大的猫,相比于重量小的猫,能放置的缆车要更少一些,则选择重量大的猫咪先放置到缆车上,产生的状态选择会少一些,所以在DFS前,先按由重到轻的顺序对猫进行排序。
![剪枝2](https://i-blog.csdnimg.cn/blog_migrate/673fc41cd5f547f967b33580ea0ddb2b.png)
4.代码实现
cat[N]:存储输入猫咪的重量
ans:记录租用缆车最少的数量
u:表示当前属于第几只猫
k:表示当前租用缆车的个数
sum[i]:存储当前已租用的缆车i的负重
代码思路:先用cat,存储输入的猫的重量,然后用sort,将猫按重量由小到大进行排序,然后再用reverse翻转排序,然后dfs(0,0)。dfs()中的剪枝,当k>=ans时,return 。当u==n时,ans更新为k。选择1,枚举已选择的k个缆车,若猫的重量加到缆车i上不超过w,则进行dfs(u+1,k),结束枚举后,进行选择2,再租多一辆缆车,将sum[k]=cat[u],然后,dfs(u+1,k+1)。
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 20;
int n, m;
int cat[N], sum[N];
int ans = N;
void dfs(int u, int k) {
if (k >= ans)return;
if (u == n) {
ans = k;
return;
}
for (int i = 0; i < k; i++) {
if (cat[u] + sum[i] <= m) {
sum[i] += cat[u];
dfs(u + 1, k);
sum[i] -= cat[u];
}
}
sum[k] = cat[u];
dfs(u + 1, k + 1);
sum[k] = 0;
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) cin >> cat[i];
sort(cat, cat + n);
reverse(cat, cat + n);
dfs(0, 0);
cout << ans << endl;
return 0;
}