0-1背包问题(动态规划)

来源:互联网 发布:希克森cba数据 编辑:程序博客网 时间:2024/05/17 02:05

01背包 : 在 N 件物品,每件物品的重量为data[1][0],data[2][0]……data[n][0],与之相对应的价值为data[1][1],data[2][1]……data[n][1], 取出若干件放在 能装重量为 M 的背包里,求能装的最大价值为?

C 版:

#include <stdio.h>#include <stdlib.h>int max(int a,int b){     if (a>b)     return a;     else return b;}int main(){      int n,m,i,j;     int data[1001][2];      int f[1001][1001];    //最优值矩阵,f[n][m]为最后所装最大价值 即 最优值      scanf("%d%d",&n,&m);  // n 表示n件物品,m 表示背包能背的最大重量 即 总承重         for(i=1;i<=n;i++)      {              scanf("%d%d",&data[i][0],&data[i][1]);  //每件物品的重量,价值      }        for(i=0;i<=m;i++)          f[0][i]=0;      for(i=0;i<=n;i++)          f[i][0]=0;      for(i=1;i<=n;i++)        {         for(j=1;j<=m;j++)            {                f[i][j]=0;                if(j>=data[i][0]) //如果第 i 个物品重量 小于等于 总承重                  {                                 f[i][j]=max(f[i-1][j],f[i-1][j-data[i][0]]+data[i][1]);                                  //按 f[i-1][j] 和 f[i-1][j-data[i][0]]+data[i][1] 哪个价值大,决定这件物品 是否被选择                                  //f[i-1][j-data[i][0]]+data[i][1] 即 j-data[i][0]的重量能背的最大价值 + 这件物品的价值                                  //f[i-1][j] 即 不装这件物品时的重量能背的最大价值              }                  else                     f[i][j]=f[i-1][j];   //如果第 i 个物品重量大于总承重         }        }       printf("%d\n",f[n][m]);      system("pause");      return 0;}
测试输入:

8 133 204 82 115 153 61 71 124 18

输出:

68


Java版:

Goods.java

public class Goods {private int weight;private int value;public Goods(int weight,int value){this.weight = weight;this.value = value;}public int getWeight() {return weight;}public int getValue() {return value;}public String toString(){return "[weight: " + weight + " " + "value: " + value + "]";}}
KnapsackProblem.java

import java.util.ArrayList;public class KnapsackProblem {private Goods[] goods;      //物品private int totalWeight;    //totalWeight 表示背包能背的最大重量private int n;              // n 表示n件物品private int[][] bestValues; //最优值矩阵private int bestValue;      //最优值private ArrayList<Goods> bestSolution;//最优解的物品组成public KnapsackProblem(Goods[] goods, int totalWeight) {              this.goods = goods;              this.totalWeight = totalWeight;              this.n = goods.length;              if (bestValues == null) {                  bestValues = new int[n+1][totalWeight+1];              }          }public void solve() {for (int i = 0; i <= n; i++) {bestValues[i][0] = 0;}for (int j = 0; j <= totalWeight; j++) {bestValues[0][j] = 0;}for (int i = 1; i <= n; i++) {         //同 C版 描述 for (int j = 1; j <= totalWeight; j++) {if (j >= goods[i - 1].getWeight()) {  int iweight = goods[i - 1].getWeight(); int ivalue = goods[i - 1].getValue();bestValues[i][j] = Math.max(bestValues[i - 1][j], bestValues[i - 1][j - iweight] + ivalue); } else {  bestValues[i][j] = bestValues[i - 1][j]; } }   } bestValue = bestValues[n][totalWeight]; if(bestSolution == null){  bestSolution = new ArrayList<Goods>(); } int tempWeight = totalWeight;for(int i=n;i >=1;i--){  if(bestValues[i][tempWeight] > bestValues[i-1][tempWeight]){ bestSolution.add(goods[i-1]);  // goods[i-1] 表示第 i 个物品                          tempWeight -= goods[i-1].getWeight();  }if(tempWeight == 0){   break;                         }} } public int[][] getBestValues() { return bestValues; } public int getBestValue() { return bestValue; }  public ArrayList<Goods> getBestSolution() { return bestSolution; }}
测试

KnapsackTest.java

public class KnapsackTest {public static void main(String[] args) {    Goods[] goods = new Goods[] {                      new Goods(3,20), new Goods(4,8),                      new Goods(2,11), new Goods(5,15),                      new Goods(3,6), new Goods(1,7),                      new Goods(1,12), new Goods(4,18)              };              int totalWeight = 12;          KnapsackProblem kp = new KnapsackProblem(goods, totalWeight);                    kp.solve();          System.out.println(" -------- 该背包问题实例的解: --------- ");          System.out.println("最优值:" + kp.getBestValue());           System.out.println("最优解【选取的物品】: ");          System.out.println(kp.getBestSolution());          System.out.println("最优值矩阵:");          int[][] bestValues = kp.getBestValues();          for (int i=0; i < bestValues.length; i++) {              for (int j=0; j < bestValues[i].length; j++) {                  System.out.printf("%-5d", bestValues[i][j]);              }              System.out.println();          }  }}
输出:

 -------- 该背包问题实例的解: --------- 最优值:68最优解【选取的物品】: [[weight: 4 value: 18], [weight: 1 value: 12], [weight: 1 value: 7], [weight: 2 value: 11], [weight: 3 value: 20]]最优值矩阵:0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    20   20   20   20   20   20   20   20   20   20   20   0    0    0    20   20   20   20   28   28   28   28   28   28   28   0    0    11   20   20   31   31   31   31   39   39   39   39   39   0    0    11   20   20   31   31   31   35   39   46   46   46   46   0    0    11   20   20   31   31   31   37   39   46   46   46   52   0    7    11   20   27   31   38   38   38   44   46   53   53   53   0    12   19   23   32   39   43   50   50   50   56   58   65   65   0    12   19   23   32   39   43   50   50   57   61   68   68   68   


时间复杂度为O(n*m),基本已经不能再优化了,但空间复杂度却可以优化到O(v)

改进版(将最优矩阵改为使用一维数组):

C++版:

#include <cstdio>#include <cstring>int bestValues[1005];int main(){ int n,m;// n 表示n件物品,m 表示背包能背的最大重量 即 总承重 int i,j; while(scanf("%d %d",&n,&m)&&(n+m)) {  int weight[1001],value[1001];  for (i=1;i<=n;i++)  {   scanf("%d",&weight[i]);   scanf("%d",&value[i]);  }  memset(bestValues,0,sizeof(bestValues));//数组初始化为0  for (i=1;i<=n;i++)//从第一个物品开始一直到第n个物品   for(j=m;j>=weight[i];j--)//从背包装满的状态开始,且第j个背包状态重量应该要大于等于第i个物品的重量    if (bestValues[j-weight[i]]+value[i]>bestValues[j]){//如果第j-1个状态放入第i个的物品,并且放入后总价值大于第j个状态的价值     bestValues[j] = bestValues[j-weight[i]]+value[i];  //则第j-1个状态时选择放入第i个的物品        } printf("%d\n",bestValues[m]); } return 0;}

0 0
原创粉丝点击