问题:给出一个序列,选出不相邻的的序列的和的最大值。
例如,有如下一个序列:
1 | 2 | 4 | 1 | 7 | 8 | 3 |
如果我们选择了第一个数,其价值为1,那么我们就不能选择2;当我们选择了7,那么其左右两边的数1和8都不能选择,现在任意给出一格序列,求其中可选的数的和的最大值。
涉及到动态规划问题,我们就要找重复的子问题和最优的子结构。
这个问题,对于每个数,我们有选或者不选两种选择方式。我给出了个数组OPT,每个值代表前N个数所能选的最大值的和。例如,OPT[7], 当我们选择7号数字的时候,那么6号数字8就不能选了,所以如果选择了7号数字,那么我们当前最大的值就是value[7]+OPT[5]. 如果不选,那么当前最大值就是钱6个数字之间的最大值OPT[6]. 对于每个数字,我们都有如下操作。其递归示意图如下所示:
图中左右子树都出现了OPT[5]和OPT[4] ,为了在计算时不重复计算相同的值,我们将每次的OPT[i] 计算后保存起来,这样在计算大于i的数的时候,就可以使用了。这也是动态规划用空间换时间的思想。
根据之前的思路,我们可以得到前N个数的可选最大值,但是对于递归的开始还需要做额外的定义:当只有一个数的时候,那么可选的只有它,最大值也是它,当只有两个数的时候,可选的就是两个数中最大的数。当总数大于三的时候,我们就可以根据前面的最大值进行递归计算了。
当然,有兴趣也可以计算每次最大值选择的数字。
该题目的公式如下:
本题目的JAVA实现算法如下,其实本体很简单,但是我加入了计算每次的选择的数字的集合,就显得有点繁琐了。
import java.util.*;
/*
* 打家劫舍问题:
* 给出一段序列:比如比,2,4,1,7,8,3
* 如果选了一个,就不能选其周围的,比如选了4,那么2,1,就不能选
* 给出最大的选择权值和
* 以及给出最大权值和的序列下标
* */
public class DJSolution {
List<List<String>> list;
int[] opt,q;
DJSolution(int[] value){
opt = new int[value.length];
q = value;
}
public boolean MaxValue() {
if(q.length==0)
return false;
else if(q.length==1) {
this.opt[0] = q[0];
return true;
}
else if(q.length==2) {
opt[0] = q[0];
opt[1] = Math.max(q[0], q[1]);
return true;
}
else {
list = new ArrayList<List<String>>();
opt[0] = q[0];
opt[1] = Math.max(q[0], q[1]);
List<String> q1 = Arrays.asList("1 "+String.valueOf(q[0]));
List<String> q2;
if(q[0]>=q[1])
q2 = Arrays.asList("1 "+String.valueOf(q[0]));
else
q2 = Arrays.asList("2 "+String.valueOf(q[1]));
list.add(q1);
list.add(q2);
Compute();
return true;
}
}
public int Compute() {
for(int i = 2;i<q.length;i++) {
List<String> res = new ArrayList<String>();
// opt[i] = Math.max(opt[i-2]+q[i], opt[i-1]);
if(opt[i-2]+q[i]>=opt[i-1]) {
opt[i] = opt[i-2]+q[i];
res.addAll(list.get(i-2));
res.add(String.valueOf(i+1)+" "+String.valueOf(q[i]));
list.add(res);
}
else {
opt[i] = opt[i-1];
res.addAll(list.get(i-1));
list.add(res);
}
}
System.out.println("前N和任务的最大值:"+Arrays.toString(opt));
System.out.println("总任务最大值:"+opt[opt.length-1]);
System.out.println("总任务最大值选择:"+list.get(list.size()-1).toString());
return opt[opt.length-1];
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] q = {1,2,5,3,3,6,2,1,6,4,4,6,3,5,7};
new DJSolution(q).MaxValue();
}
}