[华为OD] 动态规划 有一名科学家想要从一台古董电脑中拷贝文件到自己的电脑中加以研究 200

文章讲述了科学家如何利用一张3.5寸软盘和动态规划算法,解决从古董电脑中拷贝文件的问题,目标是在不超过软盘容量的情况下,使文件总大小最大化。通过计算每个文件占用的块数,将其转化为背包问题进行求解。
摘要由CSDN通过智能技术生成

题目

提示:这里可以添加本文要记录的大概内容:

题目描述:

有一名科学家想要从一台古董电脑中拷贝文件到自己的电脑中加以研究。但此电脑除了有一

个 3.5 寸软盘驱动器以外,没有任何手段可以将文件拷贝出来,而且只有一张软盘可以使

用。因此这一张软盘是唯一可以用来拷贝文件的载体。

科学家想要尽可能多地将计算机中的信息拷贝到软盘中,做到软盘中文件内容总大小最大。

已知该软盘容量为 1474560 字节。文件占用的软盘空间都是按块分配的,每个块大小为

512 个字节。一个块只能被一个文件使用。拷贝到软盘中的文件必须是完整的,且不能采

取任何压缩技术。

输入描述:

第 1 行为一个整数 N,表示计算机中的文件数量。1 <= N <= 1000。

接下来的第 2 行到第 N+1 行(共 N 行),每行为一个整数,表示每个文件的大小 Si,单

位为字节。0 <= i < N,0 <= Si

输出描述:

科学家最多能拷贝的文件总大小。

补充说明:

为了充分利用软盘空间,将每个文件在软盘上占用的块记录到本子上。即真正占用软盘空间

的只有文件内容本身。

示例 1

输入:

3

737270

737272

737288

输出:

1474542

说明:

3 个文件中,每个文件实际占用的大小分别为 737280 字节、737280 字节、737792

字节。只能选取前两个文件,总大小为 1474542 字节。虽然后两个文件总大小更大且未超过

1474560 字节,但因为实际占用的大小超过了 1474560 字节,所以不能选后两个文件。

示例 2

输入:

6

400000

200000

200000

200000

400000

400000

输出:

1400000

说明:

从 6 个文件中,选择 3 个大小为 400000 的文件和 1 个大小为 200000 的文件,得到

最大总大小为 1400000。

也可以选择 2 个大小为 400000 的文件和 3 个大小为 200000 的文件,得到的总大小

也是 1400000。


题解:

软盘总容量是1474560 字节,每个块是512 个字节,总块是Math.ceil(1474560/512) = 2880块

每个文件也可以算出它的块数,很明显的背包问题, 所以就是转换成一个固定容量的背包,放入物品的数据。直接采用动态规划的思想来做。

使用二维数组dp[i][j],每个物品占用快数为fileBlock[i],占用空间fileSpace[i];

其中i就是取前i个物品,j就是占用的块容量是j。那么dp[i][j]的意思就是在前i个物品中取物品放入块容量是j的软盘中占用的最大空间数据。

然后就是初始化:

对于dp[i][0],也就是在一个块容量为0的软盘中放入前i个文件,肯定一个都放不了,那么就是0

所以dp[i][0] = 0;

对于dp[0][j],也就是在块容量为j的的软盘总放入第一个文件,所以这里就要判断j>=fileBlock[0],才能放入,否则放不下,也是0;

那么递归的第i个物品能占用的最大空间,就有两种情况

1.一个是第i个物品不放,那么它此时就等于

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

2.第i个物品放,那么前i-1个物品占用空间应该是j-fileBlock[i]

此时dp[i][j] = dp[i-1][j-fileBlock[i]] + fileSpace[i];

实际代码计算时候,这个里面必须有一个判断,就是j必须大于等于fileBlock[i],否则会出现负值,不合乎逻辑。

以下就是代码实现:

由于要求前n个物品,在块为2880里面返回的最大空间,所以返回的应该是dp[n-1][2880]才对。

import java.util.Scanner;

public class SoftCopy {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int fileNum = sc.nextInt();

        int[] fileSpace = new int[fileNum];
        int[] fileBlock = new int[fileNum];

        for (int i = 0; i < fileNum; i++) {
            fileSpace[i] = sc.nextInt();
            fileBlock[i] = (int) Math.ceil(fileSpace[i] / 512.0);
        }
        int maxBlock = (int) Math.ceil(1474560 / 512);
        System.out.println("maxBlaock is :" + maxBlock);
        System.out.println(getDp(fileSpace, fileBlock, maxBlock));
    }

    private static int getDp(int[] fileSpace, int[] fileBlock, int maxBlock) {
        int dp[][] = new int[fileSpace.length][maxBlock + 1];
        for (int i = 0; i < fileSpace.length; i++) {
            for (int j = 0; j < maxBlock + 1; j++) {
                if (j == 0) {
                    dp[i][0] = 0;
                    continue;
                }
                if (i == 0) {
                    if (j >= fileBlock[0]) {
                        dp[0][j] = fileSpace[0];
                    } else {
                        dp[0][j] = 0;
                    }
                    continue;
                }
                if (j < fileBlock[i - 1]) {
                    dp[i][j] = 0;
                    continue;
                }
                dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - fileBlock[i - 1]] + fileSpace[i - 1]);
            }
        }

        return dp[fileBlock.length - 1][maxBlock];
    }
}

验证结果:

  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值