您的位置:首页 > 其它

动态规划--1基本知识点+01背包

2017-03-10 21:31 246 查看
1. 动态规划主要用在求解最优化问题上,与分治法类似,都是将原问题分解成多个子问题,递归求解子问题,在合并计算出最优解的过程。但是二者还是有区别的,主要区别:

(1)动态规划分解的子问题多是有互相联系性的,经分解的子问题往往不是彼此独立的;

(2)动态规划对每个子问题只求解一次,将结果保存到表中(动态规划具有多种格式,但它们具有相同的填表格式)从而避免了当子问题再次出现过程中重复求解,节省时间;

(3)动态规划实质上是一种空间换取时间的算法,它将子问题的结果存储下来避免重复计算,所以它比一般算法所占用的空间多。

(4)记忆搜索和动态规划方式类似,是一种递归调用算法,将计算过的结果保存下来,避免重复计算,但是动态规划的计算是按照一定顺序的,比如子问题b的计算需要子问题a的结果,那么先计算a再算b,记忆搜索没管这些,哪个先来先计算哪个,将其保存。

2.应用场景:

(1)具有最优子结构:问题的最优策略的子策略总是最优的;(2)子问题的重叠性:

3.步骤:描述最优解的结构,递归定义最优解,自底向上计算,合并最优解

4.典型问题:全路径最短路径的Floyd算法,0-1背包问题,矩阵链乘法,求数组中连续子串的最大和问题,最长公共子序列问题,找零钱问题

5.动态规划算法的运行时间多数情况下是两个因素的乘积:子问题的个数*每个子问题有多少种选择。比如在矩阵链相乘问题中总共有O(n^2)个子问题,每个子问题至多有n-1个选择,所以时间复杂度为O(n^3)

6.0-1背包问题

问题:n件物品,第i件物品值vi元 重wi磅(vi和wi是整数),小偷的背包最多只能装W磅,请问他该带走那几样东西?

思想:物品 j 除外剩余 n-1件物品,能带走的物品最多中 W-wj。A(j,W)表示前 j 件物品中选择最佳组合放到重为W的包中,对于物体 j,一种可能是它加入前面的物品一起放进包里,那么就是 A(j-1,W-wi)+vj 即前 j-1件物品放在中 W-wj的包里的最好效果+放入j的价值;另一种可能就是 j不放进包里 包里仍旧放前j-1中的物品 那么价值为A(j-1,W)

而A(0,W )=0 即没有物品只有包, A(j,0)=0有物品没有包。可以能到 :当 wj <W时 A(j,W)=Max( A(j-1,W-wi)+vj , A(j-1,W)) , 当wj>W时 A(j,W)= A(j-1,W)

eg:有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

class Knapsack{//物品
private String name;
private int weight;
private int value;

public Knapsack(String name,int weight,int value){
this.name=name;
this.weight=weight;
this.value=value;
}

public String getName() {
return name;
}
public int getWeight() {
return weight;
}
public int getValue() {
return value;
}
}
public class Package {
private int weightThr;//背包称重阈值
public Package(int weightThr){
this.weightThr=weightThr;
}

public int  computeItem(Knapsack[] pack){
//System.out.print("packlen="+pack.length );
if(pack.length==0) return 0;
//bestVal[i][j]表示前i件物品中放到承重为j的背包里 最大的价值
//重量+1是考虑到承重为0时防止数组越界
int[][] bestVal=new int[pack.length+1][weightThr+1];
//遍历包的称重j
for(int j=0;j<=weightThr;j++){
//遍历物品i
for(int i=0;i<=pack.length;i++){
if(i==0||j==0){
bestVal[i][j]=0;
}
else{
if(j<pack[i-1].getWeight()){//如果第i件物品重量大于总承重 则最优价值在前i-1种
bestVal[i][j]=bestVal[i-1][j];
System.out.println("物品过重"+pack[i].getWeight()+"\t此时i="+i+"\tj="+j);
}else{
int w=pack[i-1].getWeight();//物品i的重量和价格,i是从0到length的,所以第i件对应的数组下标是i-1
int v=pack[i-1].getValue();//**************此处没搞懂为啥是i-1
//动态规划得出的最有解的递归公式
bestVal[i][j]=Math.max(bestVal[i-1][j], bestVal[i-1][j-w]+v);
System.out.println("价格"+bestVal[i][j]+"\t此时i="+i+"\tj="+j);
}

}
}
}
int bestValue=bestVal[pack.length][weightThr];
System.out.println("bestValue="+bestVal[pack.length][weightThr]);
return bestValue;
}

public static void main(String[] args){
Knapsack[] pack=new Knapsack[]{ new Knapsack("a",2, 13),  new Knapsack("b",1, 10),
new Knapsack("c",3, 24), new Knapsack("d",2, 15), new Knapsack("e",4, 28),
new Knapsack("f",5, 33), new Knapsack("g",3, 20),  new Knapsack("h",1, 8) };

Package p=new Package(12);
p.computeItem(pack);
}
}


一个背包有一定的承重cap,有N件物品,每件都有自己的价值,记录在数组v中,也都有自己的重量,记录在数组w中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。

给定物品的重量w价值v及物品数n和承重cap。请返回最大总价值。

public class Backpack {
public int maxValue(int[] w, int[] v, int n, int cap) {
// write code here
int[] dp=new int[cap+1];//承重
for(int i=0;i<n;i++){
for(int j=cap;j>=w[i];j--){
dp[j]=Math.max(dp[j],dp[j-w[i]]+v[i]);
}
}
return dp[cap];
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: