多元哈夫曼编码问题

问题描述

•在一个操场的四周摆放着n堆石子,现要将石子有次序地合并成一堆。
•规定每次至少选2堆至多选k堆石子合并成新的一堆,合并的费用
  为新的一堆石子数。
•计算出将n堆石子合并成一堆的最大总费用和最小总费用。
•对于给定的n堆石子,计算合并成一堆的最大总费用和最小总费用。
  数据输入:文件的第1行有2个正整数n和k,表示有n堆石子,每次至少选2堆至多选k堆石子合并。
  第2行有n个数,分别表示每堆石子的个数。

输入示例:
7 3
45 13 12 16 9 5 22
输出示例:
593 199

问题分析

  • N堆石子最少每次搬运两堆,最大不超过k堆,求最大搬运费用和最小搬运费用的问题。

  • 所谓的最小花费即:每次尽可能多的搬运石子的堆数,但是搬运的每堆石子的个数要尽可能的少。

  • 最大花费即,尽可能少的搬运石子的堆数,最少每次搬运两堆,并且尽肯能的搬运石子数多的堆。

重要提示

  • 接下来的算法步骤我写的有错误
  • 错误原因是因为将选择的数组未进行重新排序
  • 与能力的可以尝试修改完善此代码
  • 这里附上正确的**代码**
  • 请点击跳转 正确代码的博客地址

算法步骤

1、 获取n(石子堆数),k(每次最大搬运堆数),stone数组(每堆石子的个数)

int n, k;//n-->多少堆,k-->最大每次移动多少堆
            Scanner sc = new Scanner(System.in);
            n = sc.nextInt();
            k = sc.nextInt();
            int[] stone = new int[n];
            //输入每堆的石子个数
            for (int i = 0; i < n; i++) {
                stone[i] = sc.nextInt();
            }

2、对stone数组进行排序
可以采用冒泡排序的方法,我是直接调用了java的方法
3、计算最大搬运石子费用

private static int maxfee(int[] stone) {
        ArrayList<Integer> temp = new ArrayList<>();
        int add = 0;//暂存两堆石子相加的结果
        for (int i = stone.length - 1; i >= 0; i--) {
            if (i == stone.length - 1) {
                add = stone[i] + stone[--i];//--i先减再用
                temp.add(add);//将相加的结果添加到temp数组中
            } else {
                temp.add(add + stone[i]);
                add = add + stone[i];
            }
        }
        int maxsum = 0;
        for (Integer integer : temp) {
            maxsum += integer;
        }
        return maxsum;
    }

4、计算最小搬运费用

private static void minfee(int[] stone, int k) {
        ArrayList<Integer> temp = new ArrayList<>();//临时变量temp记录移动后的每堆石子数量
        for (int i = 0; i < stone.length; i++) {
            int add = 0;//暂存两堆石子相加的结果
            for (int j = 0; j < k; j++) {
                if (i == stone.length) {//当循环的石子堆结束的时候跳出循环
                    break;
                } else {
                    add += stone[i++];
                }
            }
            if (add != stone[stone.length - 1])//若最后仅剩一堆,则这一堆没有参与搬运的操作,所以在这里直接计算minSum
                minSum += add;
            temp.add(add);
            i--;//内层循环多加了一个1,所以这里要进行减一的操作
        }
        int[] diGui = new int[temp.size()];
        for (int i = 0; i < diGui.length; i++) {
            diGui[i] = temp.get(i);
        }
        if (temp.size() != 1) {//当前堆不为一堆的话递归
            minfee(diGui, k);
        }
    }

完整代码

package cn.sg.test;

import java.util.ArrayList;
import java.util.Scanner;

import static java.util.Arrays.sort;

public class DuoYuanHaFuMan {
    private static int minSum = 0;//记录最小花费

    public static void main(String[] args) {
        int n, k;//n-->多少堆,k-->最大每次移动多少堆
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        k = sc.nextInt();
        int[] stone = new int[n];
        //输入每堆的石子个数
        for (int i = 0; i < n; i++) {
            stone[i] = sc.nextInt();
        }
        sort(stone);//调用java的方法对着n堆石子从小到大进行排序
        int maxSum = maxfee(stone);//调用函数得到最大的费用
        minfee(stone, k);//调用函数得到最小的消费
        System.out.println(maxSum + "\t" + minSum);//对计算单数据进行输出
    }

    /**
     * 计算得到最小的费用
     *
     * @param stone 当前的石头堆
     * @param k     最大移动堆的数量
     */
    private static void minfee(int[] stone, int k) {
        ArrayList<Integer> temp = new ArrayList<>();//临时变量temp记录移动后的每堆石子数量
        for (int i = 0; i < stone.length; i++) {
            int add = 0;//暂存两堆石子相加的结果
            for (int j = 0; j < k; j++) {
                if (i == stone.length) {//当循环的石子堆结束的时候跳出循环
                    break;
                } else {
                    add += stone[i++];
                }
            }
            if (add != stone[stone.length - 1])//若最后仅剩一堆,则这一堆没有参与搬运的操作,所以在这里直接计算minSum
                minSum += add;
            temp.add(add);
            i--;//内层循环多加了一个1,所以这里要进行减一的操作
        }
        int[] diGui = new int[temp.size()];
        for (int i = 0; i < diGui.length; i++) {
            diGui[i] = temp.get(i);
        }
        if (temp.size() != 1) {//当前堆不为一堆的话递归
            minfee(diGui, k);
        }
    }

    /**
     * 计算最大费用
     *
     * @param stone 当前堆
     * @return 返回最大费用
     */
    private static int maxfee(int[] stone) {
        ArrayList<Integer> temp = new ArrayList<>();
        int add = 0;//暂存两堆石子相加的结果
        for (int i = stone.length - 1; i >= 0; i--) {
            if (i == stone.length - 1) {
                add = stone[i] + stone[--i];//--i先减再用
                temp.add(add);//将相加的结果添加到temp数组中
            } else {
                temp.add(add + stone[i]);
                add = add + stone[i];
            }
        }
        int maxsum = 0;
        for (Integer integer : temp) {
            maxsum += integer;
        }
        return maxsum;
    }
}

运行截图

运行截图


代码逻辑为个人思路,若有问题欢迎指正,谢谢🎈🎈

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值