I.孤星
思路:
题目中容量太大价值太低,可以将价值和空间调换,然后反着背包dp。
变为求一个价值最大为j的时候的最小的背包的总量dp[j]的问题
注意降低时间复杂度,以及dp数组二分查找答案时要解决的小bug
错误代码:
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int MAXN = 1005;
const int MAXV = 100005;
const int INF = 1e9 + 7;
int n, m;
int w[MAXN], v[MAXN];
int dp[MAXV];
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> w[i] >> v[i];
}
// 将dp数组初始化为INF
fill(dp, dp + MAXV, INF);
dp[0] = 0;
// 预处理背包DP
for (int i = 1; i <= n; i++) {
for (int j = MAXV - 1; j >= v[i]; j--) {
dp[j] = min(dp[j], dp[j - v[i]] + w[i]);
}
}
// for(int i=MAXV-2;i>=1;i--){
// if(dp[i]==INF && dp[i+1]!=INF)dp[i]=dp[i+1];
// } 这一段是原来的错代码,应改成如下:
for (int i = MAXV-2; i >= 0; i--) dp[i] = min(dp[i], dp[i + 1]);
while (m--) {
double W;
cin >> W;
// 二分查找能达到的最大贡献值
int left = 0, right = MAXV -1;
while (left < right) {
int mid = left + (right - left + 1) / 2;
if (dp[mid] <= W) {
left = mid;
} else {
right = mid - 1;
}
}
cout << left << endl;
}
return 0;
}