第一行输入两个整数
代表预算、需要购买的物品总数。
此后
行,第
行输入三个整数
代表第
件物品的价格、重要度、主件编号。特别地,
代表该物品为主件。编号即输入顺序,从
开始。
特别地,保证全部物品的价格
均为
的倍数。
在一行上输出一个整数,代表王强可获得的最大满意度。
50 5 20 3 5 20 3 5 10 3 0 10 2 0 10 1 0
130
在这个样例中,第三、四、五件物品为主件,第一、二件物品均为第五件物品的附件。这就意味着,如果购买了第一件物品或第二件物品,则必须购买第五件物品;但是特别地,如果同时购买了第一件物品和第二件物品,则只需要购买一次第五件物品。
显然,我们可以证明,在这个样例中,购买一、二、五件商品,获得的满意度最大,为
。
1000 5 800 2 0 400 5 1 300 5 1 400 3 0 500 2 0
2200
import java.util.Scanner; //加了限制条件的背包问题 public class Main { public static int getMaxValue(int[] val, int[] weight, int[] q, int n, int w) { int[][] dp = new int[n + 1][w + 1]; for (int i = 1; i <= n; i++) { for (int j = 1; j <= w; j++) { if (q[i-1] == 0) { // 主件 if (weight[i - 1] <= j) // 用j这么多钱去买 i 件商品 可以获得最大价值 dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j- weight[i - 1]]+ val[i - 1]); } else { //附件 if (weight[i - 1] + weight[q[i - 1]] <= j) //附件的话 加上主件一起算 dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j- weight[i - 1]]+ val[i - 1]); } } } return dp[n][w]; } public static void main(String[] args) { Scanner input = new Scanner(System.in); while (input.hasNextInt()) { int n = input.nextInt(); // 总钱数 int m = input.nextInt(); // 商品个数 int[] p = new int[m]; int[] v = new int[m]; int[] q = new int[m]; for (int i = 0; i < m; i++) { p[i] = input.nextInt(); // 价格 v[i] = input.nextInt() * p[i]; // 价值 q[i] = input.nextInt(); // 主or附件 } System.out.println(getMaxValue(v, p, q, m, n)); } } }
money, things = map(int, input().split()) money = money // 10 # money都是10的整数,整除后,减小循环次数 # 三列分别表示主件,附件1,附件2 weight = [[0] * 3 for _ in range(0, things + 1)] # 价格 value = [[0] * 3 for _ in range(0, things + 1)] # 价值=价格*重要度 result = [[0] * (money + 1) for _ in range(0, things + 1)] for i in range(1, things + 1): prices, degree, depend = map(int, input().split()) # 分别为价格,重要性,主附件 prices = prices // 10 if depend == 0: # 主件 weight[i][0] = prices value[i][0] = prices * degree elif weight[depend][1] == 0: # 附件 weight[depend][1] = prices # 第一个附件 value[depend][1] = prices * degree else: weight[depend][2] = prices # 第二个附件 value[depend][2] = prices * degree # 遍历计算 for i in range(1, things + 1): # 每几件物品 for j in range(money, -1, -1): if j >= weight[i][0]: # 当前价格j可以容下第i个主件时,比较(上一个物品对应价格的价值)与(第i个物品的价值 + 余额价格对应上个物品价值) result[i][j] = max(result[i - 1][j], result[i - 1][j - weight[i][0]] + value[i][0]) # 在确定主件可容纳,并做相应计算之后,判断附件的容纳情况,如果主件都没有办法容纳,则附件必定不可容纳 if j >= (weight[i][0] + weight[i][1]): # 当可以容下第i个主件和此主件的第1个附件时,此时需要在比大小时加入当前最优,保证添加附件的结果不会反而更小 # 比较(当前价格对应上一物品的价值)与(主键价值+附件1价值+上一物品在价格(j-主键价格-附件1价格)时对应的价值) result[i][j] = max(result[i][j], result[i - 1][j], result[i - 1][j - weight[i][0] - weight[i][1]] + value[i][0] + value[i][1]) if j >= (weight[i][0] + weight[i][2]): # 可以容下第i个主件和此主件的第2个附件,此时也需要在比大小时加入当前最优,保证添加附件的结果不会反而更小 # 比较(当前价格对应上一物品的价值)与(主键价值+附件2价值+上一物品在价格(j-主键价格-附件2价格)时对应的价值), result[i][j] = max(result[i][j], result[i - 1][j], result[i - 1][j - weight[i][0] - weight[i][2]] + value[i][0] + value[i][2]) # 根据3件物品价格之和必然大于等于2件物品的规则,只有在能容纳主件和附件2时,才有判断全部容纳可能性的必要 if j >= (weight[i][0] + weight[i][1] + weight[i][2]): # 当判断通过,则判断当前值与上物品计算当前价格价值与当前3物品情况价值中最大值,同时还要比较目前最优值 result[i][j] = max(result[i][j], result[i - 1][j], result[i - 1][j - weight[i][0] - weight[i][1] - weight[i][2]] + value[i][0] + value[i][1] + value[i][2]) else: # 当前价格j不能容下第i个主件时,价值为上一个物品的对应价格的价值 result[i][j] = result[i - 1][j] print(result[things][money] * 10)
import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class Sixteen { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 总钱数 int N = scanner.nextInt(); // 购买物品个数 int m = scanner.nextInt(); int[] f = new int[N + 1]; // 分组,goods[i][0]为主件,goods[i][1]为附件1,goods[i][2]为附件2 Good[][] goods1= new Good[60][4]; for (int i = 1; i <= m; i++) { int v = scanner.nextInt(); int p = scanner.nextInt(); int q = scanner.nextInt(); Good t = new Good(v, v * p); if (q == 0) { goods1[i][0] = t; } else { if (goods1[q][1] == null) { goods1[q][1] = t; } else { goods1[q][2] = t; } } } for (int i = 1; i <= m; i++) { for (int j = N; j >= 0 && goods1[i][0] != null; j--) { //以下代码从分组中选择价值最大的。共五种情况:不选主件,选主件,选附件1和主件,选附件2和主件,选附件1和附件2和主件 Good master = goods1[i][0]; int max = f[j]; if (j >= master.v && max < f[j - master.v] + master.vp) { max = f[j - master.v] + master.vp; } int vt; if (goods1[i][1] != null) { if (j >= (vt = master.v + goods1[i][1].v) && max < f[j - vt] + master.vp + goods1[i][1].vp) { max = f[j - vt] + master.vp + goods1[i][1].vp; } } if (goods1[i][2] != null) { if (j >= (vt = master.v + goods1[i][1].v + goods1[i][2].v) && max < f[j - vt] + master.vp + goods1[i][1].vp + goods1[i][2].vp) { max = f[j - vt] + master.vp + goods1[i][1].vp + goods1[i][2].vp; } } f[j] = max; } } System.out.println(f[N]); } } class Good { int v; int vp; public Good(int v, int vp) { this.v = v; this.vp = vp; } }
有依赖的背包问题,参考http://blog.csdn.net/liang5630/article/details/8030108
转换为01背包
测试用例有问题 case通过率为80.00% 测试用例: 1738 55 20 3 0 50 2 0 120 3 0 40 3 0 100 4 0 220 2 0 40 2 0 200 3 0 90 3 0 10 3 0 230 2 0 300 1 0 70 2 0 270 1 0 300 3 0 70 5 0 300 2 0 200 1 0 210 1 0 270 2 0 180 2 0 40 2 0 110 4 0 170 4 0 110 1 0 280 4 0 50 4 0 160 2 0 10 3 0 320 3 0 10 5 0 50 2 0 230 4 0 230 1 0 150 5 0 160 5 0 90 5 0 140 3 0 140 3 0 250 5 0 330 2 0 190 3 0 230 1 0 70 2 0 50 3 0 170 5 0 100 5 0 230 5 0 120 1 0 70 2 0 50 3 0 240 1 0 220 1 0 20 5 0 20 3 0 对应输出应该为: 8090 你的输出为: 8160 #include <iostream> #include <algorithm> #define max(x,y) (x)>(y)?(x):(y) using namespace std; int main() { int N,m; //N 总钱数 m为购买物品个数 int weight[61][3]={0}; int value[61][3] = {0}; while(cin>>N>>m) { int dp[61][3201] = {0}; N /= 10; //都是10的整数倍 节约空间 int v,p,q; for(int i=1;i<=m;i++) { cin>>v>>p>>q; p = p*v; v /= 10; //按主件附件分类 第二个小标表示是第i件物品还是主件附件 if(q==0) { weight[i][q] = v; value[i][q] = p; } else if(weight[q][1]==0) { weight[q][1] = v; value[q][1] = p; } else { weight[q][2] = v; value[q][2] = p; } } //开始进行动态规划 for(int i=1;i<=m;i++) for(int j=1;j<=N;j++) { dp[i][j] = dp[i-1][j]; if(weight[i][0]<=j) { int t = max(dp[i-1][j],dp[i-1][j-weight[i][0]]+value[i][0]); if(t>dp[i][j]) dp[i][j] = t; } if(weight[i][0]+weight[i][1]<=j) { int t = dp[i-1][j-weight[i][0]-weight[i][1]]+value[i][0]+value[i][1]; if(t>dp[i][j]) dp[i][j] = t; } if(weight[i][0]+weight[i][2]<=j) { int t = dp[i-1][j-weight[i][0]-weight[i][2]]+value[i][0]+value[i][2]; if(t>dp[i][j]) dp[i][j] = t; } if(weight[i][0]+weight[i][1]+weight[i][2]<=j) { int t = dp[i-1][j-weight[i][0]-weight[i][1]-weight[i][2]]+value[i][0]+value[i][1]+value[i][2]; if(t>dp[i][j]) dp[i][j] = t; } } cout<<dp[m][N]<<endl; } return 0; }
#include <bits/stdc++.h> using namespace std; const int N = 100, M = 33000; int v[N][3], c[N][3], f[M]; int n, m, cnt; int main(){ while(scanf("%d%d", &m, &n) == 2){ memset(v, 0, sizeof(v[0]) * (n + 5)); memset(c, 0, sizeof(c[0]) * (n + 5)); memset(f, 0, sizeof(f[0]) * (m + 5)); for(int i = 1; i <= n; ++i){ int x, y, z; scanf("%d%d%d", &x, &y, &z); if(z == 0) v[i][2] = x * y, c[i][2] = x; else for(int j = 0; j <= 1; ++j) if(v[z][j] == 0) { v[z][j] = x * y; c[z][j] = x; break; } } for(int i = 1; i <= n; ++i){ for(int k = m; k >= 0; --k){ for(int s = 0; s < 4; ++s){ int val = v[i][2], cst = c[i][2]; for(int j = 0; j <= 1; ++j){ if(s & (1 << j)) val += v[i][j], cst += c[i][j]; } if(cst <= k) f[k] = max(f[k], f[k - cst] + val); } } } printf("%d\n", f[m]); } return 0; }
30 4 10 5 4 10 5 4 10 5 0 10 1 0答案是110,而不是150
N,M=3200,60 f=[0]*N #分组背包,每组有四种情况,a.主件 b.主件+附件1 c.主件+附件2 d.主件+附件1+附件2 v=[[0 for i in range(4)] for j in range(M)] #体积 w=[[0 for i in range(4)] for j in range(M)] #价值 n,m=map(int,input().split()) n=n//10#价格为10的整数倍,节省时间 for i in range(1,m+1): x,y,z=map(int,input().split()) x=x//10 if z==0: for t in range(4): v[i][t], w[i][t] = v[i][t]+x, w[i][t]+x* y elif v[z][1]==v[z][0]:#如果a==b,添加附件1(如果a=b=c=d说明没有附件) v[z][1],w[z][1] = v[z][1] + x, w[z][1] + x* y v[z][3],w[z][3] = v[z][3] + x, w[z][3] + x* y else:#添加附件2 v[z][2], w[z][2] = v[z][2] + x, w[z][2] + x* y v[z][3], w[z][3] = v[z][3] + x, w[z][3] + x* y for i in range(1,m+1): for j in range(n,-1,-1): for k in range(4): if j>=v[i][k]: f[j]=max(f[j],f[j-v[i][k]]+w[i][k]) print(10*f[n])我来发个答案吧,修改了好久终于通了。。。
#include <iostream> #include <string> using namespace std; int getMax(int x, int y){ return (x > y ? x : y); } int main(){ int N; //总钱数 int m; //希望购买的物品个数 int weight[60][3]={0}; //价格(成本) int value[60][3]={0}; //价值(重要度*价格) int f[60][3200]; //第i个物品在j容量下可以获得的最大价值 int i,j; cin >> N >> m; N/=10; //都是10的整数,先除以10,减少循环次数 //存储清单 for(int i=1;i<=m;i++){ int v; //该物品价格 int p; //该物品价值 int q; //该物品主件还是附件 cin >> v >> p >> q; v/=10; if(q==0){ //主件 weight[i][0]=v; value[i][0]=p*v; } else{ //附件 if(weight[i][1]==0){ //第一个附件 weight[i][1]=v; value[i][1]=p*v; } else{ //第二个附件 weight[i][2]=v; value[i][2]=p*v; } } } //遍历计算 for(i=1;i<=m;i++) for(j=N;j>0;j--){ if(j>=weight[i][0]) //可以容下第i个主件时,比较放第i个或者不放第i个物品的价值 f[i][j]=getMax(f[i-1][j],f[i-1][j-weight[i][0]]+value[i][0]); if(j>=weight[i][0]+weight[i][1]) //可以容下第i个主件和此主件的第1个附件时 f[i][j]=getMax(f[i-1][j],f[i-1][j-weight[i][0]-weight[i][1]]+value[i][0]+value[i][1]); if(j>=weight[i][0]+weight[i][2]) //可以容下第i个主件和此主件的第2个附件时 f[i][j]=getMax(f[i-1][j],f[i-1][j-weight[i][0]-weight[i][2]]+value[i][0]+value[i][2]); if(j>=weight[i][0]+weight[i][1]+weight[i][2]) //可以容下第i个主件和此主件的第1个附件和第2个附件时 f[i][j]=getMax(f[i-1][j],f[i-1][j-weight[i][0]-weight[i][1]-weight[i][2]]+value[i][0]+value[i][1]+value[i][2]); } cout << f[m][N]*10 << endl; }
import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner sc=new Scanner(System.in); int sum_money = 0; int num = 0; sum_money=sc.nextInt(); num=sc.nextInt(); int price[]=new int[num+1]; int val[]=new int[num+1]; int[] q = new int[num+1]; for (int i = 1; i <= num; i++) { price[i]=sc.nextInt(); val[i]=sc.nextInt()*price[i]; q[i]=sc.nextInt(); } int[][] dp=new int[num+1][sum_money+1]; /* * 初始值java默认赋值为0,其中dp[0][0...sum_money]为0,从dp[1][0...sum_money] 计算第1行,代表第一件物品 dp[i][sum_money] : 前i个物体放入容量为sum_money的背包的最大价值; dp[i-1][sum_money] : 前i-1个物体放入容量为sum_money的背包的最大价值; dp[i-1][sum_money-price[i]] : 前i-1个物体放入容量为sum_money-price[i]的背包的最大价值; dp[i][sum_money]=Math.max{dp[i-1][sum_money-price[i]]+val[i] , dp[i-1][sum_money]} */ for (int i = 1; i <=num; i++) { for (int j = 1; j <= sum_money; j++) { if(q[i]==0) { if(price[i]<=j) dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-price[i]]+val[i]); } if(q[i]>0) { if(price[i]+price[q[i]]<=j) dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-price[i]-price[q[i]]]+val[i]+val[q[i]]); } } } System.out.println(dp[num][sum_money]); } }
#include <iostream> #include <algorithm> #include <string> #include <string.h> using namespace std; int main() { int v[100]; //价格 int q[100]; //主件or附件 int vp[100]; //权重*价格 int dp[100][3000]; int N,m; while(cin >> N >> m) { for(int i=0;i<100;i++) memset(dp[i], 0, sizeof(dp[i])); int tmpw; //临时变量用于保存权重 //初始化赋值 for(int i=1;i<=m;i++) { cin >> v[i] >> tmpw >> q[i]; vp[i] = v[i] * tmpw; } for(int i=1;i<=m;i++) //一共有m组数据 { for(int j=1;j<=N;j++) //j为价格,从0到N进行遍历 { if(q[i] == 0) { if(v[i]<=j) //如果j >= v[i] { dp[i][j] = max(dp[i-1][j-v[i]]+vp[i], dp[i-1][j]); //将上一行同列的元素值与 上一行同列减去v[i]加上vp[i]的值做比较 }else{ dp[i][j] = dp[i-1][j]; //复制上一行的数据 } } else { if(v[i] + v[q[i]] <= j) //判断条件需要j> (v[i] + v[q[i]]) { dp[i][j] = max(dp[i-1][j-v[i]]+vp[i], dp[i-1][j]); }else{ dp[i][j] = dp[i-1][j]; } } } } cout << dp[m][N] << endl; } return 0; }
2200400*3+500*2 =2200 ,为什么不是800*2+400*5=3600 呢(1主1附件) , 1000*5> 3600 > 2000
n,m=map(int,input().split()) f=[0]*n #购物单总价值 #分组背包,每组有四种情况,a.主件 b.主件+附件1 c.主件+附件2 d.主件+附件1+附件2 v=[[0 for i in range(4)] for j in range(m+1)] #每组的资金 w=[[0 for i in range(4)] for j in range(m+1)] #每组的重要度 n=n//10#价格为10的整数倍,节省时间 for i in range(1,m+1): x,y,z=map(int,input().split()) x=x//10 if z==0: # 主件,同时给每个组合初始化主件的金额跟重要度 for t in range(4): v[i][t], w[i][t] = v[i][t]+x, w[i][t]+x* y elif v[z][1]==v[z][0]:#附件且a==b,意味着附件1没加入,这时候累加b跟d情况 v[z][1],w[z][1] = v[z][1] + x, w[z][1] + x* y v[z][3],w[z][3] = v[z][3] + x, w[z][3] + x* y else:#附件且a!=b,意味着附件1加入了附件2没加入,这时候累加c跟d情况 v[z][2], w[z][2] = v[z][2] + x, w[z][2] + x* y v[z][3], w[z][3] = v[z][3] + x, w[z][3] + x* y # m:加入购物单的物品个数上限 for i in range(1, m+1): # n:购物总资金上限,只能倒序遍历,因为背包的思维是可用空间从大到小,求当前每个子状态的最优, # 如果顺序遍历,背包容量变大,之前遍历的子状态的最优结论就被推翻了 for j in range(n, -1, -1): for k in range(4): if j >= v[i][k]: # 将每组的购物资金 整体视为 一个容量,这样才不会出现主件重复放入的情况,这也是其他答案犯错的地方 # f[j]:表示总花费为j钱时的最大购物价值 f[j] = max(f[j], f[j-v[i][k]]+w[i][k]) print(10*f[n])
首先应该明确示例的定义,示例对于理解题目来说非常关键 输入第一行,1000 是总预算(total_budget) 5 指总的物品数量(包含主件附件) 第二行之后的就是每个物品的描述数据了 第一列800 400 300 400 500 这些表示物品价格,第二列的数字是物品的重要度 第三列很关键,,非0 数字都表示这个物品是附件,0 表示这个物品是主件。 非0的同时这个数字是和主件有绑定关系的,比如是1,表示这个是主件1 的附件,那么主件1 是谁就很关键, 找错主件结果就完全不对了,所以这里要考虑我们在存储主件的时候,同时要保留的是主件的索引,从题目中来看,主件从1 开始 所以遇到第1行是0 的数据,就得更新主件索引为1(i + 1),同时将附件数据绑定上去,这样算是成功了一半了。 多重背包很关键的一点考虑在物品不能重复购买,这就说明你在预算计算的时候,需要考虑是倒序遍历 必须的,不然重复计算了,这点可能比较难理解,可以带入一下就能想的比较清晰,还有一点就是遍历时的stop 点 v - 1 , 当j >= v 的时候进行遍历即可 思考,先从主件开始,主件+附件1 主件+附件2 主件+附件1+附件2,依次更新dp[j] #购物单 这是一个多重背包问题,购买主件后,可以不购买附件,也可以购买1件或者2件附件,不能重复购买,求最大的满意度 #首先定义这个输入输出 ''' 1000 总预算 5物品数量 800 2 满意度 0 主件0 400 5 1 主件0 的附件1 300 5 1 主件0 的附件2 400 3 0 主件1 500 2 0 主件2 ''' import sys total_budget, num_items = map(int, sys.stdin.readline().rstrip().split()) #存储主件 main_items = [] attachments = {} i = 0 while i < num_items: v, p, q = map(int, sys.stdin.readline().rstrip().split()) if q == 0: #存储主件 main_items.append((v, p, i + 1)) else: #附件 if q not in attachments: attachments[q] = [] attachments[q].append((v, p)) i += 1 dp = [0] * (total_budget + 1) #选择主件 for v, p, idx in main_items: #从后往前遍历,避免重复选择 for j in range(total_budget, v - 1, -1): dp[j] = max(dp[j], dp[j - v] + v * p) #计算附件 if idx in attachments: for av, ap in attachments[idx]: if j >= v + av: dp[j] = max(dp[j], dp[j - v - av] + v * p + av * ap) if len(attachments[idx]) == 2: av1, ap1 = attachments[idx][0] av2, ap2 = attachments[idx][1] if j >= av1 + av2 + v: dp[j] = max(dp[j], dp[j - v - av1 - av2] + v * p + av1 * ap1 + av2 * ap2) print(dp[total_budget])
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int money = in.nextInt(); int num = in.nextInt(); int[][] prices = new int[num + 1][3]; int[][] weights = new int[num + 1][3]; for (int i = 1; i <= num; i++) { int price = in.nextInt(); int weight = in.nextInt(); int zfj = in.nextInt(); weight *= price; if (zfj == 0) { prices[i][0] = price; weights[i][0] = weight; } else if (prices[zfj][1] == 0) { prices[zfj][1] = price; weights[zfj][1] = weight; } else { prices[zfj][2] = price; weights[zfj][2] = weight; } } int[] dp = new int[money + 1];// dp数组 for (int i = 1; i <= num; i++) {// 遍历物品 for (int j = money; j >= 0; j -= 10) {// 遍历money int a = j - prices[i][0]; int b = j - prices[i][0] - prices[i][1]; int c = j - prices[i][0] - prices[i][2]; int d = j - prices[i][0] - prices[i][1] - prices[i][2]; int e = weights[i][0]; int f = weights[i][0] + weights[i][1]; int g = weights[i][0] + weights[i][2]; int h = weights[i][0] + weights[i][1] + weights[i][2]; dp[j] = a >= 0 ? Math.max(dp[j], dp[a] + e) : dp[j];// 是否购买主件 dp[j] = b >= 0 ? Math.max(dp[j], dp[b] + f) : dp[j];// 是否购买主件和附件1 dp[j] = c >= 0 ? Math.max(dp[j], dp[c] + g) : dp[j];// 是否购买主件和附件2 dp[j] = d >= 0 ? Math.max(dp[j], dp[d] + h) : dp[j];// 是否购买主件和附件1和附件2 } } System.out.println(dp[money]);// 输出结果 } }
背包问题, 增加限定条件不影响 用dp。。。。 #include <iostream> #include <algorithm> #include <string> #include <string.h> using namespace std; int main() { int v[61]; int dp[61][32001]; int q[61]; int vp[61]; int N,m; while(cin >> N >> m) { for(int i=0;i<61;i++) memset(dp[i], 0, sizeof(dp[i])); int tmpw; for(int i=1;i<=m;i++) { cin >> v[i] >> tmpw >> q[i]; vp[i] = v[i] * tmpw; } for(int i=1;i<=m;i++) { for(int j=1;j<=N;j++) { if(q[i] == 0) { if(v[i]<=j) { dp[i][j] = max(dp[i-1][j-v[i]]+vp[i], dp[i-1][j]); } } else { if(v[i] + v[q[i]] <= j) { dp[i][j] = max(dp[i-1][j-v[i]]+vp[i], dp[i-1][j]); } } } } cout << dp[m][N] << endl; } return 0; }
import java.util.Scanner; import java.*; public class Main{ public static void main(String[] args){ // 输入数据 Scanner in = new Scanner(System.in); int n = in.nextInt(); int m = in.nextInt(); Goods[] goods = new Goods[m+1]; for(int i=1; i<=m; i++){ int v = in.nextInt(); int p = in.nextInt(); int q = in.nextInt(); goods[i] = new Goods(v,p,q); // 如果商品是附件 if(q > 0){ if(goods[q].addID1 == 0) goods[q].addID1 = i; else goods[q].addID2 = i; } } // 处理网格 int[][] dp = new int[m+1][n+1]; for(int i=1; i<=m; i++){ // 第 i 个商品 int v1 = 0, v2 = 0, v3 = 0, v4 = 0; int w1 = 0, w2 = 0, w3 = 0, w4 = 0; // 1. 主件 v1 = goods[i].v; w1 = v1*goods[i].p; // 2. 主件 + 附件1 if(goods[i].addID1 != 0){ v2 = v1 + goods[goods[i].addID1].v; w2 = w1 + goods[goods[i].addID1].v*goods[goods[i].addID1].p; } // 3. 主件 + 附件2 if(goods[i].addID2 != 0){ v3 = v1 + goods[goods[i].addID2].v; w3 = w1 + goods[goods[i].addID2].v*goods[goods[i].addID2].p; } // 4. 主件 + 附件1 + 附件2 if(goods[i].addID1 != 0 && goods[i].addID2 !=0){ v4 = v2 + v3 - v1; w4 = w2 + w3 - w1; } for(int j=1; j<=n; j++){ if(goods[i].q > 0) { dp[i][j] = dp[i-1][j]; // 附件行数据 会跟它的 主件行数据 一模一样 continue; // 跳过附件 } // 对于主件行数据而言,它需要考虑四种情况里,自己选择哪种能够利益最大化 dp[i][j] = dp[i-1][j]; if(v1 <= j) dp[i][j] = Math.max(dp[i][j], w1+dp[i-1][j-v1]); if(v2 <= j && v2 != 0) dp[i][j] = Math.max(dp[i][j], w2+dp[i-1][j-v2]); if(v3 <= j && v3 != 0) dp[i][j] = Math.max(dp[i][j], w3+dp[i-1][j-v3]); if(v4 <= j && v4 != 0) dp[i][j] = Math.max(dp[i][j], w4+dp[i-1][j-v4]); } } // 输出数据 System.out.println(dp[m][n]); } } // 商品类 class Goods{ int v; int p; int q; int addID1 = 0; // 附件1的ID int addID2 = 0; // 附件2的ID public Goods(int v, int p, int q){ this.v = v; this.p = p; this.q = q; } }
''' 01背包问题 题意:所有的物品都分为两类,一类是主件,另一类是附件,附件有附件1和附件2 其中,每一个附件都有它的主件,选取它的主件之后才能选取附件 在取某件物品时,我们只需要从以下四种方案中取最大的那种方案: 1.只取主件 2.取主件+附件1 3.取主件+附件2 4.既主件+附件1+附件2。很容易得到如下状态转移方程: f[i,j]=max(f[i-1,j]) f[i-1,j-a[i,0]]+a[i,0]*b[i,0] f[i-1,j-a[i,0]-a[i,1]]+a[i,0]*b[i,0]+a[i,1]*b[i,1] f[i-1,j-a[i,0]-a[i,2]]+a[i,0]*b[i,0]+a[i,2]*b[i,2] f[i-1,j-a[i,0]-a[i,1]-a[i,2]]+a[i,0]*b[i,0]+a[i,1]*b[i,1]+a[i,2]*b[i,2] 含义: f[i,j]表示用j元钱,买第i类物品,所得的最大价值 a[i,0]表示第i类物品主件的价格 a[i,1]表示第i类物品第1个附件的价格 a[i,2]表示第i类物品第2个附件的价格 b[i,0],b[i,1],b[i,2]分别表示主件、第1个附件和第2个附件的重要度。 需要在满足金额money内,买到最大价值的物品。价值=价格*重要度 ''' money, things = map(int, input().split()) money = money // 10 #money都是10的整数,整除后,减小循环次数 #三列分别表示主件,附件1,附件2 weight = [[0] * 3 for _ in range(0, things + 1)] #价格 value = [[0] * 3 for _ in range(0, things + 1)] #价值=价格*重要度 result = [[0] * (money + 1) for _ in range(things + 1)] for i in range(1, things + 1): prices, degree, depend = map(int, input().split()) #分别为价格,重要性,主附件 prices = prices // 10 if depend == 0: #主件 weight[i][0] = prices value[i][0] = prices * degree elif weight[depend][1] == 0: #附件 weight[depend][1] = prices #第一个附件 value[depend][1] = prices * degree else: weight[depend][2] = prices #第二个附件 value[depend][2] = prices * degree #遍历计算 for i in range(1, things + 1): for j in range(money, 9, -10): if j >= weight[i][0]: #可以容下第i个主件时,比较不放第i个或者放第i个物品的价值 result[i][j] = max(result[i - 1][i], result[i - 1][j - weight[i][0]] + value[i][0]) else: result[i][j] = result[i - 1][j] if j >= (weight[i][0] + weight[i][1]): #可以容下第i个主件和此主件的第1个附件时 result[i][j] = max(result[i - 1][j], result[i - 1][j - weight[i][0] - weight[i][1]] + value[i][0] + value[i][1]) else: result[i][j] = result[i - 1][j] if j >= (weight[i][0] + weight[i][2]): #可以容下第i个主件和此主件的第2个附件时 result[i][j] = max(result[i - 1][j], result[i - 1][j - weight[i][0] - weight[i][2]] + value[i][0] + value[i][2]) else: result[i][j] = result[i - 1][j] if j >= (weight[i][0] + weight[i][1] + weight[i][2]): #可以容下第i个主件和此主件的第1个附件和第2个附件时 result[i][j] = max(result[i - 1][j], result[i - 1][j - weight[i][0] - weight[i][1] - weight[i][2]] + value[i][0] + value[i][1] + value[i][2]) else: result[i][j] = result[i - 1][j] print(result[things][money] * 10) --------------------- 作者:萝卜luo 来源:CSDN 原文:https://blog.csdn.net/luohaobo/article/details/92852970 版权声明:本文为博主原创文章,转载请附上博文链接!
n, m = map(int, input().split()) prices = [0] * m degree = [0] * m depend = [0] * m # 在这里记录的主件下标是从1开始的 for i in range(m): prices[i], degree[i], depend[i] = map(int, input().split()) result = [[0] * (n + 1) for i in range(m + 1)] for i in range(1, m + 1): # 选择商品 for j in range(10, n + 1, 10): # 价格(10的整数) if depend[i - 1] == 0: # 如果为主件 if prices[i - 1] <= j: result[i][j] = max(result[i - 1][j], result[i - 1][j - prices[i - 1]] + prices[i - 1] * degree[i - 1]) elif prices[i - 1] + prices[depend[i - 1] - 1] <= j: # 如果为配件,钱比配件大;然后比较加与不加谁大(空出主件+该配件的钱,然后加上主件和配件与重要度的乘积) result[i][j] = max(result[i - 1][j], result[i - 1][j - prices[i - 1] - prices[depend[i - 1] - 1]] + prices[i - 1] * degree[ i - 1] + prices[depend[i - 1] - 1] * degree[depend[i - 1] - 1]) print(result[m][int(n / 10) * 10]) # n可能非10的倍数 --------------------- 来源:牛客网讨论区