动态规划思想
1.什么是动态故规划思想呢?
动态规划是一种算法设计的思想,主要是讲一个问题划分成几个更小的而问题进行求解,(其实很像递归)
2. 它的特点是什么?
它的各个子问题不是相互独立的,他们包含公共子问题,因此子问题的的解会被重复多次求解
3.动态规划与分治算法的异同点:
相同点: 做法是都会将一个大问题分解成多个子问题。
不同点: 以子问题是否相互独立 进行区别,动态规划子问题相互独立,分治算法中的被分解的那些子问题都是相互独立的;并通过递归的方式最终得到整个问题的解。
下边我们用一个0-1背包问题对动态规划问题进一步进行解析:
背包容量是c 6
不同物品对应的重量(w)分别为: 1 ,2, 3, 4
相对应的价值(value)分别为 : 2,3, 4, 6
求给背包中放置那些物品可保证价值最大?
分析: 我分先列张表,将所有情况都分析下
将背包划分六个子包,然后进行求解,然后推论出公式(从后往前):
w=4,v=6,j=1,2,3,时,dp[i][j]=dp[i+1][j]=0;
j=4时,dp[i][j]=max{0,v[i]+dp[i+1][j-w[i]]}=max{0,6+0}=6;
j=5 dp[i][j]类似的用(3)式
到w=3时,同样 按照此方法
装入背包的而物品最优,dp[i][j]: 表示选择了i个物品时的价值,(i 表示选择物品的个数,j 表示背包容量),
(1) dp[i][0]=dp[0][i]=0;
(2)j>w(i) dp[i][j]=v[i+1][j]
(3) j<=w(i) dp=max{dp[i+1][j],v[i]+ddp[i+1][j-w(i)]};
下边我们放代码
import java.util.Arrays;
/*dp[i][j]:装入物品最大价值
* i:选择物品的个数(行)
* j:背包容量(列)
* */
public class 动态规划求解背包问题 {
static int []w={1,2,3,4};
static int[]v={2,3,4,6};
static int c=6;
static int [][]dp=new int [w.length+1][c+1];
static int [][]path=new int[w.length][c+1];
public static void main(String[] args) {
jude(w,v,c,dp);
System.out.println();
}
public static void jude(int[]w,int[]v,int c,int[][]dp){
int n=w.length-1;
for (int j = 1; j <=c; j++) {
if(w[n]>j){
dp[n][j]=0;
}else {
dp[n][j]=v[n];
}
}
for (int i = n-1; i >=0; i--) {//代表行
for (int i1 = 1; i1 <=c; i1++) {//代表列
if(w[i]>i1){
dp[i][i1]=dp[i+1][i1];
}if(w[i]<=i1){
dp[i][i1]=Math.max(dp[i+1][i1],v[i]+dp[i+1][i1-w[i]] );
}
}
}
for (int i = 0; i < w.length; i++) {
for (int i1 = 1; i1 <=c; i1++) {
System.out.print(dp[i][i1]+"\t ");
}
System.out.println();
}
//打印路径
for (int i = 0; i < w.length-1; i++) {
if (dp[i][c] != dp[i + 1][c]) {
//选择了wupin
System.out.println(w[i] + " ");
c -= w[i];
}
}
if(dp[w.length-1][c]>0){
System.out.println(w[w.length-1]+" ");
}
System.out.println();
}
}
运行结果:
0 0 0 0 0 0 0 0
0 2 3 5 6 8 9
0 0 3 4 6 7 9
0 0 0 4 6 6 6
0 0 0 0 6 6 6
2
4
2.动态规划解决轮船装在问题
解决方法同上,我们尽可能将承重能力大的船装满,这里没有价值上的考虑
public class 动态规划解决轮船装载 {
static int []w={8,9,10,13,7,14,12,5};
static int c1=50;
static int c2=28;
static int [][]dp=new int[w.length][c1+1];
public static void main(String[] args) {
jude();
System.out.println();
}
public static void jude() {
int n = w.length - 1;
for (int j = 1; j <= c1; j++) {
if (w[n] > j) {
dp[n][j] = 0;
} else {
dp[n][j] = w[n];
}
}
for (int i = n - 1; i >= 0; i--) {
for (int j = 1; j <= c1; j++) {
if (w[i] > j) {
dp[i][j] = dp[i + 1][j];
} else {
dp[i][j] = Math.max(dp[i + 1][j], w[i] + dp[i + 1][j - w[i]]);
}
}
}
for (int i = 0; i < w.length; i++) {
for (int j = 1; j <= c1; j++) {
System.out.print(dp[i][j] + "\t ");
}
System.out.println();
}
int[] x = new int[w.length];
int c1w = c1;
for (int i = 0; i < w.length - 1; i++) {
if (dp[i][c1w] != dp[i + 1][c1w]) {
x[i] = 1;
System.out.print(w[i] + " ");
c1w -= w[i];
}
}
if (dp[w.length - 1][c1] > 0) {
System.out.println(x[w.length - 1] = 1);
}
System.out.println("装入c1:" + c1);
for (int i = 0; i < x.length; i++) {
if (x[i] == 1) {
System.out.print(w[i] + " ");
}
}
System.out.println();
System.out.println("装入c2:" + c2);
for (int i = 0; i < x.length; i++) {
if (x[i] == 0) {
System.out.print(w[i] + " ");
}
}
}
}
这个结果的二维数组太大我就不放结果了。
总结:动态规划这块就时大问题就化成哥哥子问题的解,最后求解出总最优解。