题解 P5365 【[SNOI2017]英雄联盟】
这是一道标准的背包问题——
题目传送门
更好的阅读体验?
废话不多说,不会的童鞋们跟我来!
1.逐步分析
既然是背包问题,最重要的当然就是转移方程了,所以转移方程是什么呢?
题中,我们知道了英雄的数量,每一种英雄的数量以及价值,没错,这就是所谓的多重背包。
当然,这道题不同的地方是,我们要求的是最少花费的钱数,所以我们不妨先在开始读入价钱的时候,将所有的价钱累加起来,算出最多需要花费的钱数,当作总钱数。
//读入部分
cin>>n>>m;
for (int i=1;i<=n;i++) cin>>k[i];
for (int i=1;i<=n;i++) {
cin>>c[i];
qm+=c[i]*k[i];//累加
}
而在转移方程中,我们可以用第一维表示取前
dp[i][j]=max(dp[i][j],dp[i][j-x*c[i]]*x);
其中,
而考虑到维度优化,根据传统的背包模板 经过思考,我们可以将第一维“取前几件物品”省略,即:
dp[j]=max(dp[j],dp[j-x*c[i]]*x);
对了,花0个Q币的方案数默认为1,即:
dp[0]=1;
2.AC代码及注释
#include<bits/stdc++.h>//万能明星头
using namespace std;
const int N=1000001;
long long n,m,k[N],c[N],qm,dp[N]={1},ans;
//如题
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);//亲测优化程度基本大于快读
cin>>n>>m;
for (int i=1;i<=n;i++) cin>>k[i];
for (int i=1;i<=n;i++) {
cin>>c[i];
qm+=c[i]*k[i];
}//输入部分
for (int i=1;i<=n;i++){//枚举前i件物品
for (int j=qm;j>=0;j--){//倒序枚举花j个Q币
for (int x=0;x<=k[i]&&x*c[i]<=j;x++){//枚举买x个皮肤
dp[j]=max(dp[j],dp[j-x*c[i]]*x);//转移方程
}
}
}
while (ans<=qm&&dp[ans]<m) ans++;//满足条件就++
cout<<ans<<endl;//输出
return 0;//好习惯要保持
}
3.完结撒花!
本次题解就这么愉快地结束啦!感谢您坚持看到了最后!
如果还有什么不懂的问题,欢迎在评论区回复哦,我会第一时间解答哒!
当然,如果您看懂了,就点个赞纪念一下您的成长吧!