这题同样是退化的01背包问题,主要来实验了一下关于背包问题的一些优化策略
未优化
#include <iostream>
#include <algorithm>
using namespace std;
int arr[50005];
int hay[5005];
int main()
{
int c, h;
cin >> c >> h;
for(int i = 1; i <= h; i++)
cin >> hay[i];
arr[0] = {0};
for(int i = 1; i <= h; i++)
for(int j = c; j >= hay[i]; j--)
arr[j] = max(arr[j], arr[j-hay[i]]+hay[i]);
cout << arr[c];
return 0;
}
优化1:提高循环下限
这个优化参考了良月澪二的“背包九讲——全篇详细理解与代码实现”,贴出地址:
在之前的循环体中,背包容量j下限被设置为,因为对于状态数组,
时代表剩余容量的下标小于0,相当于非法地址。对于接下来的优化,假设对于第i件以后的物品全部选取,那么剩余的背包容量为
,如果剩余容量小于0,那么可以确定一定有比它更好的方案,换而言之,所有可能最优的方案满足
。将这个不等式与之前的
联立,就可以得到新的循环下限
#include <iostream>
#include <algorithm>
using namespace std;
int arr[50005];
int hay[5005];
int sum[5005];
int main()
{
int c, h;
cin >> c >> h;
for(int i = 1; i <= h; i++)
{
cin >> hay[i];
sum[i] = sum[i-1] + hay[i];
}
arr[0] = {0};
for(int i = 1; i <= h; i++)
{
int bound = max(hay[i], c-(sum[h]-sum[i]));
for(int j = c; j >= bound; j--)
arr[j] = max(arr[j], arr[j-hay[i]]+hay[i]);
}
cout << arr[c];
return 0;
}
对于这道题,一般优化效果不明显
优化2:针对极端数据,找到最优解后直接输出
#include <iostream>
#include <algorithm>
using namespace std;
int arr[50005];
int hay[5005];
int sum[5005];
int main()
{
int c, h;
cin >> c >> h;
for(int i = 1; i <= h; i++)
{
cin >> hay[i];
sum[i] = sum[i-1] + hay[i];
}
arr[0] = {0};
for(int i = 1; i <= h; i++)
{
int bound = max(hay[i], c-(sum[h]-sum[i]));
for(int j = c; j >= bound; j--)
{
arr[j] = max(arr[j], arr[j-hay[i]]+hay[i]);
if(arr[j] == c) //最优解:稻草容量刚好与马车相等
{
cout << c;
return 0;
}
}
}
cout << arr[c];
return 0;
}