《重启21》
9.7——去哪儿笔试-01背包问题
前言
博主又又又n次参加秋招笔试了,这次所属有点打脸,让博主这种想速成算法的人感觉到了绝望。。。笔试一共3到算法题,前两道对于经常算题的人来说是频见题,不过对于博主这种就没怎么算明白了。。。其中一个01背包问题,博主很久就听说过了,但做的少没有出现过相应题目,又没去了解。昨天就翻大车了。。。
题目
大意:冬奥会的体操比赛,有i个动作,每个动作有对应的体力消耗n和得分m,然后运动员有体力t。如果运动员要尽量高的成绩要怎么做动作?
假设:运动员不做重复的动作,i>0,n>0,m>0,0<=t
输入:
10 [[1,1],[2,3],[3,5],[5,10],[6,8],[7,9],[9,10]]
18
ps:第一排的10代表t,二维数组为动作和得分,如[5,10]5为体力消耗,10为得分数
第二排为运动员的得分
要求:<2ms
代码
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 运动员可得到的最高分
* @param t int整型 运动员体力值
* @param actions int整型二维数组 二维数组i为动作号 actions[i][0]为动作i+1消耗体力,actions[i][1]为动作i+1得分
* @return int整型
*/
public int maxScore(int t,int[][] actions){
int len=actions.length+1; //多少个动作+1(因为我要加入0号动作消耗0获取0分)
int[] acts = new int[len]; // 每个动作对应的体力
int[] score = new int[len]; // 每个动作对应的价值
acts[0]=0;
for (int i=1;i<len;i++){
acts[i]=actions[i-1][0];
}
score[0]=0;
for (int i=1;i<len;i++){
score[i]=actions[i-1][1];
}
int[][] v=new int[len][t+1];
for(int i=0;i<len;i++){
for(int j=0;j<t+1;j++){
if(i==0){
v[i][j]=0; // 边界情况:V(0,j)=0
}else if(j==0){
v[i][j]=0; // 边界情况:V(0,j)=0
}else{
if(j<acts[i]){
v[i][j]=v[i-1][j]; // 包的容量比当前该物品体积小,装不下,此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j);
}else {
v[i][j]=Math.max(v[i - 1][j], v[i - 1][j - acts[i]] + score[i]);// 还有足够的容量可以装当前该物品,但装了当前物品也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即V(i,j)=max{V[i-1,j],V[i-1,j-acts(i)]+score[i]}。
}
}
}
}
return v[len-1][t];
}
// int[] item=new int[len];
// Arrays.fill(item,0);
//
// // 从最优解,倒推回去找
// int j = t;
// for (int i = len-1; i > 0; i--) {
// if (v[i][j] > v[i - 1][j]) {// 在最优解中,v[i][j]>v[i-1][j]说明选择了第i个商品
// item[i] = 1;
// j = j - acts[i];
// }
// }
//
// System.out.print("包内物品的编号为:");
// for (int i = 0; i < len; i++) {
// if (item[i] == 1) {
// System.out.print(i + " ");
// }
// }
// System.out.println("----------------------------");
}