题解 | #购物单# 01背包问题的变体
购物单
https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4
#include <iostream> #include <vector> using namespace std; //动态规划 0-1背包问题 //所有涉及价格的地方,由于价格全部能被10整除,全部都/10减少遍历次数,包括可供支配的总价格N、每件商品的价格price int main() { int N,m; cin>>N>>m; N/=10; int price,priority,hash;//用来输入每件物品的价格、重要度、是否是谁的附件 vector<vector<int>>data(m+1,vector<int>(6,0)); //用来存放商品信息,行为1~m,0行认为是无商品。存放最多m件主件商品,0、1列存放主件商品的价格和重要度,2、3列存放第一个附件(如果有)的价格和重要度,4、5列存放第二个附件(如果有)的价格和重要度 for(int i=1;i<=m;i++){ cin>>price>>priority>>hash; //如果是主件 if(hash==0){ data[i][0]=price/10; data[i][1]=priority; } else if(hash>0&&data[hash][2]==0){ //此时这件物品是data[hash]的附件,且附件1的位置还没有登记数据,那这件商品就登记到附件1的位置 data[hash][2]=price/10; data[hash][3]=priority; } else if(hash>0&&data[hash][2]!=0){ //这件物品是data[hash]的附件,且附件1的位置已经有数据了,就放到附件2的位置 data[hash][4]=price/10; data[hash][5]=priority; } } //初始化dp方程 dp[i][j]的含义是,总钱数为j的情况下,在[0,i]范围内购买物品所产生的最大价值(0是不购买,最大可以取到m)。初始化第一行第一列 vector<vector<int>>dp(m+1,vector<int>(N+1,0)); //所有的dp[i][0]=0,不需要额外再初始化了,dp[0][j]表示有j块钱的时候不购买商品,dp[0][j]=0 //递推 for(int i=1;i<=m;i++){ //给每个主件商品及附件商品的价格和重要度拿出来(如果没有就是0),便于后面写递推 int price0=data[i][0]; int priority0=data[i][1]; int price1=data[i][2]; int priority1=data[i][3]; int price2=data[i][4]; int priority2=data[i][5]; for(int j=1;j<=N;j++){ //1) 只考虑买主件商品 if(j<price0){dp[i][j]=dp[i-1][j];}//钱不够 else{//钱够 dp[i][j]=max(dp[i-1][j],dp[i-1][j-price0]+price0*priority0); } //2) 再买一件附件1 dp[i][j]此时记录了购买主件后的价值,若钱不够买,dp[i][j]不变,可以省略,若钱够买,和购买附件后的价值做比较,有更大的值才赋值给dp[i][j] // if(j<price0+price1){dp[i][j]=dp[i][j];}//如果不够买直接值不变,这句就省略了 if(j>=price0+price1){ dp[i][j]=max(dp[i][j],dp[i-1][j-price0-price1]+price0*priority0+price1*priority1); } //同理,再买一件2 if(j>=price0+price2){ dp[i][j]=max(dp[i][j],dp[i-1][j-price0-price2]+price0*priority0+price2*priority2); } //类似的,1 2都买 if(j>=price0+price1+price2){ dp[i][j]=max(dp[i][j],dp[i-1][j-price0-price1-price2]+price0*priority0+price1*priority1+price2*priority2); } } } cout<<dp[m][N]*10<<endl; }