对于允许最后一次操作溢出背包,在反向遍历(01背包变种),需要进行max(0, j-weight)限制
对于有额外操作的情况,最后不要降维,可能会因为重复访问引起错误,直接二维解决即可。
#include <algorithm>
#include <climits>
#include <iostream>
#include <iterator>
#include <vector>
using namespace std;
using ll =long long;
int main() {
int n, m;
cin >> n >> m;
vector<pair<int, int>> coal(n);
for (int i = 0; i < n; i++) cin >> coal[i].first >> coal[i].second;
sort(coal.begin(), coal.end(), [](pair<int, int>& p1, pair<int, int>& p2) {
return p1.first < p2.first;
});
ll minTime = INT_MAX;
while ( !coal.empty() && coal.back().first * 2 >= m) {
minTime = min(minTime, static_cast<ll>(coal.back().second / 2));
coal.pop_back();
}
n = coal.size();
if(n==0) {
cout<<minTime;
return 0;
}
vector<vector<ll>> dp(n+1,vector<ll>(m+1, INT_MAX)), magic(n+1,vector<ll>(m+1, INT_MAX));
dp[0][0] = 0;
magic[0][0] = 0;
for (int i = 1; i <= n; i++) {
int x = coal[i - 1].first;
int y = coal[i - 1].second;
dp[i]=dp[i-1];
magic[i]=magic[i-1];
for (int j = m; j >= 0; j--) {
//no magic
int k = max(0, j - x);
if (dp[i-1][k] != INT_MAX) dp[i][j] = min(dp[i][j], dp[i-1][k] + y);
if (magic[i-1][k] != INT_MAX) magic[i][j] = min(magic[i][j], magic[i-1][k] + y);
//use magic
k = max(0, j - 2 * x);
if (dp[i-1][k] != INT_MAX) magic[i][j] = min(magic[i][j], dp[i-1][k] + y / 2);
}
}
cout << min(magic[n][m], minTime);
//cout << magic[n][m];
}
// 64 位输出请用 printf("%lld")

京公网安备 11010502036488号