题意
n 种药草,每种药草有价值 vi,需要花费时间 ti。求时限 m 内能获得的最大价值。
思路
不能更裸的01背包,问题在于 m 可以大到 1e9。于是老师就教了一个神奇的dp。
简单地说就是把状态用 vector 存下来,一步转移之后,按价值从大到小排序,把价值小,时间反而多的状态删掉。据老师讲状态数是可证地不超过某个值(时间太久忘了)。
链接
https://vjudge.net/contest/175446#problem/D
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 110;
typedef long long LL;
typedef pair<LL, LL> P;
LL n, m;
P A[maxn];
vector<P> dp[maxn];
bool cmp(P a, P b)
{
if(a.first == b.first) return a.second < b.second;
return a.first > b.first;
}
int main()
{
// freopen("in.txt", "r", stdin);
while(cin >> n >> m)
{
for(int i = 1; i <= n; i++)
cin >> A[i].second >> A[i].first;
sort(A+1, A+1+n, cmp);
// for(int i = 1; i <= n; i++)
// cout << A[i].first << " " << A[i].second << endl;
for(int i = 0; i <= n; i++)
dp[i].clear();
dp[0].push_back(P(0, 0));
for(int i = 1; i <= n; i++)
{
LL tt = dp[i-1].size();
for(LL j = 0; j < tt; j++)
{
dp[i].push_back(dp[i-1][j]);
if(dp[i-1][j].second + A[i].second <= m) dp[i].push_back(P(dp[i-1][j].first+A[i].first, dp[i-1][j].second + A[i].second));
}
sort(dp[i].begin(), dp[i].end(), cmp);
for(LL j = 1; j < dp[i].size(); j++)
if(dp[i][j].second >= dp[i][j-1].second){
dp[i].erase(dp[i].begin()+j);
j--;
}
}
cout << dp[n][0].first << endl;
}
return 0;
}