动态规划解决0-1背包问题

(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,...,n0-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));
 }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值