(1)、基本原理
动态规划算法(Dynamic Programming Algorithm, DPA)与分治法类似,其基本思想是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划法求解的问题,经分解得到的子问题往往不是互相独立的,若用分治法解这类问题,则分解得到的子问题数目太多,以至于最后解决原问题需要耗费过多的时间。在用分治法求解时,有些子问题被重复计算了许多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算。为了达到此目的,可以用一个表来记录所有已解决的子问题的答案。这就是动态规划法的基本思想。
(2)、解决0-1背包算法分析
0-1背包问题的最优子结构,设(y1,y2,...,yn)是所给0-1背包问题的一个最优解,则(y2,y3,...,yn)是经过一次选择后的0-1背包问题的最优解。0-1背包问题的递归关系,设当前子问题的最优值为m(i,j),即m(i,j)使背包容量为j,可选择物品为i,i+1,...,n时0-1背包问题的最优值。由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式:
当i=n时,若j>=wn,则m(i,j)=vn;若0<=j<wn,则m(i,j)=0。
当i<n时,若j>=wi,则m(i,j)=max{m(i+1,j),m(i+1,j-wi)+vi};若0<=j<wi,则m(i,j)=m(i+1,j)。
(3)、JAVA程序实现
import javax.swing.*;
public class Knapsack extends JFrame{
final JScrollPane scrollPane = new JScrollPane();
public static JTextArea resulttextArea;
public JLabel l1 = new JLabel("最优解");
public JLabel l3 = new JLabel("所用时间");
public static JTextField t1 = new JTextField();
public static JTextField t2 = new JTextField();
final JLabel label = new JLabel();
final JLabel label_1 = new JLabel();
public Knapsack(){
this.setResizable(false);
this.setTitle("分支限界算法计算0-1背包");
this.getContentPane().setLayout(null);
this.setBounds(100, 100, 670, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
scrollPane.setBounds(190, 25, 454, 293);
getContentPane().add(scrollPane);
resulttextArea = new JTextArea();
resulttextArea.setEditable(false);
scrollPane.setViewportView(resulttextArea);
label.setHorizontalTextPosition(SwingConstants.RIGHT);
label.setHorizontalAlignment(SwingConstants.RIGHT);
label.setText("最优解:");
label.setBounds(10, 42, 66, 18);
getContentPane().add(label);
t1.setHorizontalAlignment(SwingConstants.RIGHT);
t1.setHorizontalAlignment(SwingConstants.RIGHT);
t1.setBounds(80, 42, 66, 18);
getContentPane().add(t1);
label_1.setHorizontalTextPosition(SwingConstants.RIGHT);
label_1.setHorizontalAlignment(SwingConstants.RIGHT);
label_1.setText("所用时间:");
label_1.setBounds(10, 75, 66, 18);
getContentPane().add(label_1);
t2.setHorizontalAlignment(SwingConstants.RIGHT);
t2.setHorizontalAlignment(SwingConstants.RIGHT);
t2.setBounds(80, 75, 66, 18);
getContentPane().add(t2);
}
void display(int[] v,int[] w,int c,int n,int[][] m)
{
int jMax = Math.min(w[n-1]-1,c);
for(int j=0;j<=jMax;j++)
{
m[n][j] = 0;
}//初始化
for(int j=w[n-1];j<c;j++)
{
m[n][j]=v[n];
}
for(int i=n-1;i>0;i--)
{
jMax=Math.min(w[i]-1,c);
for(int j=0;j<=jMax;j++)
{
m[i][j]=m[i+1][j];
}
for(int j=w[i];j<c;j++)
{
m[i][j]=Math.max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
}
}
System.out.println("出来的循环m[0][c-1]:"+m[0][c-1]);
System.out.println("出来的循环m[1][c-1]:"+m[0][c-1]);
m[0][c-1]=m[1][c-1];
if(c>=w[0])
{
m[0][c-1]=Math.max(m[0][c-1],m[1][c-w[0]]+v[0]);
}
System.out.println("-------------------------------------------");
System.out.println("此0-1背包问题的最优解为:"+m[0][c-1]);
System.out.println("物品的选择(‘0’代表没有选择,‘1’代表选择)如下:");
System.out.println("-------------------------------------------");
t1.setText(""+m[0][c-1]);
}
void taceback(int[] w,int c,int n,int[][] m,int [] x)
{
resulttextArea.append("物品的选择(‘0’代表没有选择,‘1’代表选择)如下:/n");
for(int i=0;i<n;i++)
{
if(m[i][c-1]==m[i+1][c-1]) x[i]=0;
else {
x[i]=1;
c-=w[i];
}
System.out.println("x["+i+"]="+x[i]);
resulttextArea.append("x["+i+"]="+x[i]+"/n");
}
if(m[n-1][c-1]==1) x[n-1]=1;
else x[n-1]=0;
System.out.println("x["+n+"]="+x[n-1]);
resulttextArea.append("x["+n+"]="+x[n-1]+"/n");
System.out.println("-------------------------------------------");
}
public static void main(String[] args)
{
final int c=1000;
final int n=50;
int[] v={220,208,198,192,180,180,
165,162,160,158,155,130,
125,122,120,118,115,110,
105,101,100,100,98,96,
95,90,88,82,80,77,
75,73,70,69,66,65,
63,60,58,56,50,30,
20,15,10,8,5,3,
1,1};
int[] w={80,82,85,70,72,70,
66,50,55,25,50,55,
40,48,50,32,22,60,
30,32,40,38,35,32,
25,28,30,22,50,30,
45,30,60,50,20,65,
20,25,30,10,20,25,
15,10,10,10,4,4,
1,1};
int[][] m=new int[n][c];
int[] x=new int[n];
long start = System.currentTimeMillis();
Knapsack k=new Knapsack();
k.setVisible(true);
k.display(v,w,c,n-1,m);
k.taceback(w,c,n-1,m,x);
long end = System.currentTimeMillis();
t2.setText((end - start)+"ms");
System.out.println("/n Time consuming: " + (end - start));
}
}