阿里笔试 7.27 第二题 JAVA
第二题
有个藏宝架有n层,每层的宝物数量不一,每个宝物都有其价值,现在要求拿出m个宝物,并且需要遵守规则:
- 每次只能拿选定层的两端的宝物
- 要拿出的m个宝物的总价值是各种方案里最大的
输入: n m
下面每行代表每层,且第一个数是这层宝物的数量k,后面的则是k个宝物的价值
4 1 2 4 5
5 1 2 4 5 5
样例:
2 3
2 3 2
4 1 4 1 5
输出:5+3+2=10
主要方法:DP
先用滑动窗口生成每一行取0-m个对应的最大值的一个矩阵 M:(m + 10) * n:
以样例为例:
0 3 5 5
0 5 6 10
之后做一个(m + 1)* n 的dp表:
类似背包的思想,从上往下,一层一层拿:
先只拿第一层:
0 3 5 5
(意义就是只拿第一层的时候,取的个数与对应最大总价值)
再加入第二层:
0 3 5 5
0 5 8 10转移方程:dp[i] [j] = max( p[i-1] [j-k] + M[i] [k], dp[i-1] [j]) (0 <= k <= j)
时间复杂度:O(m^2*n)
空间复杂度:O(m*n)
代码
自测了一下,应该是好使,感兴趣的可以参考一下:
import java.util.*;
class test{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
List list = new LinkedList();
while(in.hasNext()){
int k = in.nextInt();
int[] arr = new int[k];
for (int i = 0; i < k; i++){
arr[i] = in.nextInt();
}
list.add(arr);
}
LinkedList cur = new LinkedList();
helper(list, m, cur);
int res = helper(cur, m, n);
System.out.println(res);
}
private static int helper(List cur, int m, int n){
int[][] dp = new int[n][m + 1];
for (int i = 0; i < n; i++){
for (int j = 0; j <= m; j++){
if (i == 0 && j != 0) {
dp[i][j] = cur.get(0)[j-1];
}else if (j == 0) {
dp[i][j] = 0;
}else {
int curMax = dp[i-1][j];
for (int k = 0; k <= j; k++){
curMax = Math.max(curMax, dp[i-1][j-k] + cur.get(i)[k]);
}
dp[i][j] = curMax;
}
}
}
return dp[n-1][m];
}
private static void helper(List list, int m, List resList){
for (int[] cur : list){
resList.add(genRow(cur, m));
}
}
private static int[] genRow(int[] arr, int m){
int[] res = new int[m+1];
res[0] = 0;
for (int i = 1; i <= m; i++){
res[i] = maxSum(arr, i);
}
return res;
}
private static int maxSum(int[] arr, int m){
int sum = 0;
for (int i : arr) sum += i;
if (m > arr.length) return sum;
int res = Integer.MAX_VALUE;
for (int i = 0; i <= m; i++){
int cur = 0;
for (int j = 0; j < arr.length - m; j++){
cur += arr[i+j];
}
res = Math.min(res, cur);
}
return sum - res;
}
}
360集团公司氛围 350人发布