0/1背包问题

0/1背包问题属于比较典型的算法了,它的关键点在于“拿不拿”。

现在我们有一个容量为M公斤的背包,n件物品,她们的重量分别是W1、W2.......Wn,他们的价值分别为C1、C2.......Cn,求能获得的最大价值。

输入:

第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);

第2...N+1行:每行输入两个整数Wi,Ci,表示每个物品的重量和价值。

输出:

一个数,表示最大价值。

输入案例:

背包容量和物品个数:10 4

物品质量和价值:

2 1

3 3

4 5

7 9

画表格分析:

关于“拿”还是“不拿”,关键在于背包容量是否允许“拿”,拿了之后的价值是否大于不拿的价值。

DP

w[i]

v[i]

0

1

2

3

4

5

6

7

8

9

10

0

0

0

0

0

0

0

0

0

0

0

0

0

2

1

0

0

1

1

1

1

1

1

1

1

1

3

3

0

0

1

3

3

4

4

4

4

4

4

4

5

0

0

1

3

5

5

6

8

8

9

9

7

9

0

0

1

3

5

5

6

9

9

10

12

注:其中w[]代表物品的重量,v[]代表物品的价值,第一行的0-10代表背包的容量。

如果背包的容量小于该物品重量,那么只能选择“不拿”,那么

dp[i][j]=dp[i-1][j];

如果背包容量不小于物品质量,那么就需要比较“拿”的价值最大,还是不拿的价值最大。(也许减去w[i]你会有疑问,在下面总代码中会进行解释)

dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);

输出dp数组(也就是上面表格的右部):

最后一个元素12就是最大价值。

总代码:

public class beibao01 {
    public static void main(String[] args) {
         Scanner sc=new Scanner(System.in);
         System.out.println("请分别输入背包的容量和物品的个数:");
         int cont=sc.nextInt();
         int num=sc.nextInt();
         System.out.println("请分别输入背包的物品重量和价值:");
         int []w=new int[num+1];
         int []v=new int[num+1];
         int [][]dp=new int[num+1][cont+1];
         for(int i=1;i<=num;i++) {
             w[i]=sc.nextInt();//物品重量
             v[i]=sc.nextInt();//物品价值
         }
         
         for(int i=1;i<=num;i++) {
             for(int j=1;j<=cont;j++) {
                 if(j<w[i]) {
                     dp[i][j]=dp[i-1][j];
                 }else {
                     //dp[i-1][j]是指“不拿”的情况,当前的dp值直接等于上一层的值。
                     //dp[i-1][j-w[i]]+v[i]指的是“拿”的情况是指上一层的dp的值加上当前物品的价值。
                     //也许会有个疑问,为什么是dp[i-1][j-w[i]]+v[i]中减去的是w[i],而不是1,因为可能你上一个也没有“拿”,如果-1的话意思就是你上一个一定是“拿”的,如果上一个“不拿”呢?甚至说上上一个“不拿”呢?当你减去当前物品的重量的话,那么剩下的就是上一次“拿”的时候总重量,这样得到的dp才是上一次“拿”的时候的总价值。
                     dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-w[i]]+v[i]);
                 }
             }
         }
         for(int i=0;i<=num;i++) {
             for(int j=0;j<=cont;j++) {
                 System.out.print(dp[i][j]+"  ");
             }
             System.out.println("");
             System.out.println("");
         }
         
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值