存钱罐最小值问题(java)

1.主观题 (100分)

实验六:使用动态规划算法解决存钱问题(完成实验报告三、四、五、六的内容)


一、实验目的

       练习使用动态规划算法解决实际问题(使用Java语言实现)。

二、实验内容

【问题描述】

给定一个空存钱罐的重量和这个存钱罐最多能装进去的重量,现在需要在不打破这个存钱罐的情况下猜测里面最少的钱。每种钱的数量不做限制,条件是必须装满,同时给出每种钱币的价值和重量。 

【输入】

输入的第一行数据包含整数T,表示测试用例的数量。每个测试用例的第一行都包含两个整数e和f(1<=e<=f<=10000),分别表示空存钱罐和装满硬币的存钱罐的重量(以克记)。第二行包含一个整数n(1<=n<=500),表示硬币的总数量。接下来的n行每行都包含两个整数p和w,分别表示硬币的面值和重量。

【输出】

对每个测试用例,都输出一行,包含”存钱罐内的最小金额是 x“,其中x是存钱罐内的最小金额。若无法确定,则输出”这是不可能的“

【输入输出示例】

样例输入:

 10 110 

 2 

 1 1 

 30 50 

 10 110 

 2 

 1 1 

 50 30 

 1 6 

 2 

 10 3 

 20 4

样例输出:

存钱罐内的最小金额是60

存钱罐内的最小金额是100

这是不可能的

【思路提示】

这是一个完全背包问题。

三、 程序代码

(1)MinWeigh

package maxweightminvalue;

import java.util.Scanner;

public class MinWeight {
        private int coinSort;//硬币的种类
        private int e;//存钱罐自身重量
        private int f;//存钱罐装满最大的重量
        private int v;//存钱罐的容量
        private int[] dp=new int[10001];//dp数组
        Coin[] coins;//硬币的面值和重量数组

        public void inputData() {
            int exit = 1;
            Scanner scanner = new Scanner(System.in);
            //System.out.println("请输入测试的次数:");
            while (exit==1) {
                    coins = new Coin[1000];
                    System.out.println("请输入存钱罐自身重量和装满最大的重量:");
                    e = scanner.nextInt();
                    f = scanner.nextInt();
                    v = f - e;
                    System.out.println("请输入硬币的种类:");
                    coinSort = scanner.nextInt();
                    System.out.println("请输入每种硬币的面值和重量:");
                    for (int i = 0; i < coinSort; i++) {
                        coins[i] = new Coin();
                        coins[i].value = scanner.nextInt();
                        coins[i].weight = scanner.nextInt();
                    }
                display();
                System.out.println("是否想继续测试(继续测试输入1,退出请输入0):");
                exit=scanner.nextInt();
            }
        }

        public int load(){
            dp[0]=0;
            for(int i=1;i<=v;i++){
                dp[i]=500000001;//设置数组中能设置的最大值,便于比较筛选出最小值
            }
            for(int i=0;i<coinSort;i++){
                for(int j=0;j<=v;j++){
                    if (j-coins[i].weight<0)
                        dp[j]=dp[j];//因为装不下所以没有变化
                    else//能装下则需要进行装下物品的最小值比较
                        dp[j]=Math.min(dp[j],dp[j-coins[i].weight]+coins[i].value);//状态转移方程
                }
            }
            return dp[v];
        }

        public void display(){
                if(load()!=500000001){
                    System.out.println("存钱罐内的最小金额是"+load());
                }
                else {//数组最后值没有变化则说明当前金币种类与金币质量不匹配
                    System.out.println("这是不可能的");
                }
        }



    }



(2)Coin

package maxweightminvalue;

public class Coin {
    public int value;
    public int weight;
    public int number;
}

(3)TestMinWeight

package test;

import maxweightminvalue.MinWeight;

public class TestMinWeight {
    public static void main(String[] args) {
        MinWeight minWeight =new MinWeight();
        minWeight.inputData();
    }
}

四、 实验结果(含程序运行截图)

EM%M4R(`89{6U`QCS~12_2D.png

五、 出现问题及解决方法

本次实验为完全背包问题与01背包不同的是一种物品可以放入多个,所以我们再装入物品的时候需要考虑装入该物品的数量,正常情况下是求能装入背包的最大值但是本题是装入的最小值,所以再求状态转移方程时有困难,以及在求解数组时候的思想比较难考虑到,也是参考了网上的思路后才开始动手的。下面说一下不同于最大值的点:

(1)开始时不同于其他的求解最大值的背包问题是要对dp数组进行赋值为0的初始化而是进行对于dp数组中的每一个元素来复制成该整型变量所能承受的最大值。

for(int i=1;i<=v;i++){
   dp[i]=500000001;//设置数组中能设置的最大值,便于比较筛选出最小值
}

因为要筛选出最小值所以赋值为其他怕影响最小值比较时因为原始数组初始化存放数据的影响导致比较错误。

(2)求解状态转移方程

       求解状态方程网上有很多做法比如在ij的·循环内再加一个对应的放入某种物品数量的k变量来进行记录但是适应于最大值不适应于最小值,所以问题很多,修改的时候不能单纯的进行将最大值改成最小值,所以在查找资料后发现了下面的状态方程:

dp[j]=Math.min(dp[j],dp[j-coins[i].weight]+coins[i].value);//状态转移方程

       该状态转移方程为循环求解给出的钱币种类以及质量,比较更小的那个进行存放。而且是一种钱币比较一次,但是最终结果都存放在一维的dp数组中,最后循环到最后的值如果能正好将存钱罐体积填满则dp数组的最后一个值不为500000001,如果没办法填满则最后的dp数组的值仍然为500000001没有变化,则给出的钱币种类不能将体积填满,所以是不可能的。

六、 实验心得

本次实验心得为算法还是要多拓展自己的思路要有自己思考的过程,争取有一天能够自己想出好的算法。

 第一篇博客,确实有在网上查资料的成分,大家有什么问题欢迎在评论区留言呀,有什么好的想法我也想学习一下~


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值