165. 小猫爬山
每次安排猫的时候有两种方法:用已经使用过的车来装、用没有使用过的车来装
需要进行剪枝:当 state 已经大于等于已经得到的答案,那么就直接回溯。
剪枝前TLE,剪枝之后耗时94ms
#include <iostream>
#include <algorithm>
using namespace std;
int n, w, res;
int c[20], rest[20];
// 已经安排了 u 只猫,使用了 state 辆车
void dfs(int u, int state)
{
// 这个剪枝非常重要,没有就会超时
if (state >= res)
return;
// 安排好了n只猫
if (u == n) {
res = min(res, state);
return;
}
// 用已经使用过的车来装
for (int i = 0; i < state; i++) {
if (rest[i] >= c[u]) {
rest[i] -= c[u];
dfs(u + 1, state);
rest[i] += c[u];
}
}
//用没有使用过的车来装
rest[state] -= c[u];
dfs(u + 1, state + 1);
rest[state] += c[u];
}
int main(void)
{
cin >> n >> w;
res = n;
for (int i = 0; i < n; i++) {
cin >> c[i];
rest[i] = w;
}
dfs(0, 0);
cout << res << endl;
return 0;
}
将小猫按重量从大到小排序,可以减少搜索树的分支数目。
优化后耗时30ms
#include <iostream>
#include <algorithm>
using namespace std;
int n, w, res;
int c[20], rest[20];
bool cmp(int a, int b)
{
return a > b;
}
// 已经安排了 u 只猫,使用了 state 辆车
void dfs(int u, int state)
{
// 这个剪枝非常重要,没有就会超时
if (state >= res)
return;
// 装好了n只猫
if (u == n) {
res = min(res, state);
return;
}
// 用已经使用过的车来装
for (int i = 0; i < state; i++) {
if (rest[i] >= c[u]) {
rest[i] -= c[u];
dfs(u + 1, state);
rest[i] += c[u];
}
}
//用没有使用过的车来装
rest[state] -= c[u];
dfs(u + 1, state + 1);
rest[state] += c[u];
}
int main(void)
{
cin >> n >> w;
res = n;
for (int i = 0; i < n; i++) {
cin >> c[i];
rest[i] = w;
}
sort(c, c + n, cmp);
dfs(0, 0);
cout << res << endl;
return 0;
}