有华为OD考试扣扣交流群可加:948025485
可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳od1336
了解算法冲刺训练
有一名科学家想要从一台古董电脑中拷贝文件到自己的电脑中加以研究。
但此电脑除了有一个3.5寸软盘驱动器以外,没有任何手段可以将文件持贝出来,而且只有一张软盘可以使用。
因此这一张软盘是唯一可以用来拷贝文件的载体。
科学家想要尽可能多地将计算机中的信息拷贝到软盘中,做到软盘中文件内容总大小最大。
已知该软盘容量为1474560
字节。文件占用的软盘空间都是按块分配的,每个块大小为512
个字节。一个块只能被一个文件使用。拷贝到软盘中的文件必须是完整的,且不能采取任何压缩技术。
第1
行为一个整数N
,表示计算机中的文件数量。1 ≤ N ≤ 1000
.
接下来的第2
行到第N+1
行(共N
行),每行为一个整数,表示每个文件的大小Si
,单位为字节
。
0 ≤ i < N`,`0 ≤ Si`` <= 1474560
科学家最多能拷贝的文件总大小
为了充分利用软盘空间,将每个文件在软盘上占用的块记录到本子上。即真正占用软盘空间的只有文件内容本身。
3
737270
737272
737288
1474542
3个文件中,每个文件实际占用的大小分别为737280
字节、737280
字节、737792
字节。只能选取前两个文件,总大小为1474542
字节。虽然后两个文件总大小更大且未超过1474560
字节,但因为实际占用的大小超过了1474560
字节,所以不能选后两个文件。
6
400000
200000
200000
200000
400000
400000
1400000
从6
个文件中,选择3
个大小为400000
的文件和1
个大小为200000
的文件,得到最大总大小为1400000
。
也可以选择2
个大小为400000
的文件和3
个大小为200000
的文件,得到的总大小也是1400000
我们需要在N
个文件中挑选出若干个文件,使得总文件大小尽可能地大,因此本题属于一个典型的背包问题。
但本题中存在一个坑,文件必须按照块进行储存,且一个块只能储存一个文件。块的大小是512
。
假设此时要储存一个大小为513
的文件,就必须使用2
个块来储存,且由于第二个块即使没有填满也不能再用于其他文件的存储,故占用的空间为1024
。
由于软盘总容量为1474560
字节,一共包含1474560 // 512 = 2880
个块,而每一个文件所占用的块数,也可以很方便地通过ceil(file_i ``/ 512)
得到,故我们可以将问题进行转化为如下描述:
对于已知容量为2880
的背包,我们知道每一个文件所占空间ceil(file_i ``/ 512)
和价值file_i
,我们如何进行选择使得背包的总价值尽可能地大。
这就将题干描述的复杂情况,转化为了一个相对容易解决的路径无关、求和最大值的01背包问题了。其解法类似于【DP】2023A-工作安排
# 题目:2023B-通过软盘拷贝文件
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:背包DP
# 代码看不懂的地方,请直接在群上提问
from math import ceil
# 输入文件数目
n = int(input())
# 创建价值列表和空间列表
# 价值列表储存每一个文件的有效内容的字节数
# 空间列表储存每一个文件实际占用的块数
value_lst = list()
space_lst = list()
# 遍历n次
for _ in range(n):
value = int(input())
value_lst.append(value)
space_lst.append(ceil(value / 512))
# 背包容量,即 1474560 // 512 = 2880 个块
m = 2880
# 构建长度为(m+1)的dp数组
dp = [0] * (m+1)
# 路径无关,先遍历每一个文件,后遍历背包容量
for i in range(n):
# 分别获得第i份文件的实际内容字节数value和所占用块数space
value = value_lst[i]
space = space_lst[i]
# 01背包,逆序遍历背包的前置容量pre_space
# 遍历的起点可以从m-space开始,
# 这样可以保证每个pre_space+space都不会超过m
for pre_space in range(m-space, -1, -1):
# 获取pre_space的对应最大价值pre_value
pre_value = dp[pre_space]
# 从前置容量pre_space出发,加上当前文件容量space
# 所占据的总容量为cur_space
cur_space = pre_space + space
# 如果先前用pre_space空间能够获得的有效字节数pre_value
# 加上当前有效字节数value
# 比原先的dp[cur_space]更大(默认为0),则更新dp[cur_space]
dp[cur_space] = max(dp[cur_space], pre_value + value)
# 输出dp数组中的最大值,即为答案
print(max(dp))
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] value_lst = new int[n];
int[] space_lst = new int[n];
for (int i = 0; i < n; i++) {
int value = scanner.nextInt();
value_lst[i] = value;
space_lst[i] = (int) Math.ceil(value / 512.0);
}
int m = 2880;
int[] dp = new int[m + 1];
for (int i = 0; i < n; i++) {
int value = value_lst[i];
int space = space_lst[i];
for (int pre_space = m - space; pre_space >= 0; pre_space--) {
int pre_value = dp[pre_space];
int cur_space = pre_space + space;
dp[cur_space] = Math.max(dp[cur_space], pre_value + value);
}
}
int maxResult = 0;
for (int i = 0; i <= m; i++) {
maxResult = Math.max(maxResult, dp[i]);
}
System.out.println(maxResult);
}
}
#include
#include
#include
#include
using namespace std;
int main() {
int n;
cin >> n;
vector<int> value_lst(n);
vector<int> space_lst(n);
for (int i = 0; i < n; i++) {
int value;
cin >> value;
value_lst[i] = value;
space_lst[i] = ceil(static_cast<double>(value) / 512);
}
int m = 2880;
vector<int> dp(m + 1, 0);
for (int i = 0; i < n; i++) {
int value = value_lst[i];
int space = space_lst[i];
for (int pre_space = m - space; pre_space >= 0; pre_space--) {
int pre_value = dp[pre_space];
int cur_space = pre_space + space;
dp[cur_space] = max(dp[cur_space], pre_value + value);
}
}
int maxResult = 0;
for (int i = 0; i <= m; i++) {
maxResult = max(maxResult, dp[i]);
}
cout << maxResult << endl;
return 0;
}
时间复杂度:O(NM)
。其中N
为文件个数,M
为背包的最大容量,对于本题恒有M = 2880
空间复杂度:O(M)
。1维dp
数组所占空间。
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
可查看链接 大厂真题汇总 & OD真题汇总(持续更新)
绿色聊天软件戳 od1336
了解更多