题目描述
有 v(1≤v≤100,000)v(1\le v\le 100,000)v(1≤v≤100,000) 元钱和 n(1≤n≤50)n(1\le n\le 50)n(1≤n≤50) 种游戏平台,购买每种游戏平台的价格是 pi(1≤pi≤1,000)p_i(1\le p_i\le 1,000)pi(1≤pi≤1,000),第 iii 种游戏平台支持 gi(1≤gi≤10)g_i(1\le g_i\le 10)gi(1≤gi≤10) 种游戏,每种游戏的价格和对答案的贡献分别是 gpj(1≤gpj≤100)gp_j(1\le gp_j\le 100)gpj(1≤gpj≤100) 和 pvj(1≤pvj≤1,000,000)pv_j(1\le pv_j\le 1,000,000)pvj(1≤pvj≤1,000,000),只有购买了游戏平台才能购买相应平台下的游戏,求用这 vvv 元钱产生答案的最大值。
算法分析
定义 f[i][j]f[i][j]f[i][j] 表示前 iii 种游戏平台花费 jjj 元不购买第 iii 种游戏平台时的最大答案,d[i][j]d[i][j]d[i][j] 表示前 iii 种游戏平台花费 jjj 元购买第 iii 种游戏平台时的最大答案,设计状态转移方程。
可以使用滚动数组优化,时间复杂度大概是 O(nv)O(nv)O(nv),有十倍的常数。
代码实现
#include <cstdio>
#include <cstring>
#include <algorithm>
const int maxn=55;
const int maxv=(int)1e5+5;
int f[2][maxv],d[2][maxv];
int main() {
int n,v;scanf("%d%d",&n,&v);
memset(f,0x80,sizeof(f));f[0][0]=0;
memset(d,0x80,sizeof(d));d[0][0]=0;
for(int i=1;i<=n;++i) {
int p,g;scanf("%d%d",&p,&g);
for(int j=0;j<=v;++j) {
f[i&1][j]=std::max(f[(i-1)&1][j],d[(i-1)&1][j]);
if(j>=p) d[i&1][j]=std::max(f[(i-1)&1][j-p],d[(i-1)&1][j-p]);
}
for(int j=1;j<=g;++j) {
int gp,pv;scanf("%d%d",&gp,&pv);
for(int k=v;k-gp>=p;--k) d[i&1][k]=std::max(d[i&1][k],d[i&1][k-gp]+pv);
}
}
int ans=0;
for(int i=0;i<=v;++i) ans=std::max(ans,std::max(f[n&1][i],d[n&1][i]));
printf("%d\n",ans);
return 0;
}