【问题标题】:Optimization Problem on files split based on size基于大小拆分文件的优化问题
【发布时间】:2021-04-29 06:43:37
【问题描述】:

我面临一个优化问题,我想找到一种能够解决它的算法。

Hyphotesis:文件大小总和至少大于 15 MB。所以总大小是 [15 MB; +∞]。为简单起见,将无穷大视为 100 GB,

问题:我有一个大小在 3 KB 到 4 MB 之间的文件列表。我必须压缩这些文件,并且我需要保证将它们压缩在一起之前的文件大小总和在 15 MB 和 150 MB 之间。 有没有已知的算法来处理这个问题?为了不让算法在计算要求方面花费太多,可以不最小化块的数量(因此每个块不是必须尽可能大)。

谢谢, 朱塞佩

【问题讨论】:

  • 那么,您只需从文件列表中创建最大 150MB 的 zip 文件吗?
  • 也许是背包问题?
  • 到目前为止,这似乎是对加号和较少或相等运算符的练习。什么是优化角度?你想最大化什么?
  • @dratenik 我想最大化每个 zip 文件的大小。
  • 只有上限,这是一个众所周知的问题:装箱(bin 大小为 150MB)。如果您将下限作为最小化垃圾箱的代理:删除它并使用 wiki 上链接的启发式/近似值进行垃圾箱打包!如果出于其他充分的理由(连同最大)需要它,您可能会遇到麻烦:这可能是 NP-hard(子集和,分区),尽管我不确定。实际上,如果同时存在最小和最大界限:使用整数编程!

标签: java arrays algorithm optimization maximize


【解决方案1】:

我们可以调整著名的首次拟合递减算法来做到这一点。

import random

K = 1000
B = 1
KB = K * B
MB = K * KB


class File:
    def __init__(self):
        self.size = random.randrange(3 * KB, 4 * MB)


class Chunk:
    def __init__(self, max_chunk_size):
        self.free = max_chunk_size
        self.files = []

    def add(self, file):
        if self.free < file.size:
            return False
        self.free -= file.size
        self.files.append(file)
        return True

    def enlarge(self, delta_free):
        assert delta_free >= 0
        self.free += delta_free

    def size(self):
        return sum(file.size for file in self.files)


def first_fit_decreasing(files, min_chunk_size, max_chunk_size):
    chunks = []
    for file in sorted(files, key=lambda file: file.size, reverse=True):
        for existing_chunk in chunks:
            if existing_chunk.add(file):
                break
        else:
            if len(chunks) >= 2:
                chunks[-2].enlarge(min_chunk_size)
            new_chunk = Chunk(max_chunk_size - min_chunk_size)
            new_chunk.add(file)
            chunks.append(new_chunk)
    if chunks[-1].size() < min_chunk_size:
        chunks[-2].enlarge(min_chunk_size)
        for file in chunks[-1].files:
            chunks[-2].add(file)
        del chunks[-1]
    return chunks


def test(n):
    files = [File() for i in range(n)]
    min_chunk_size = 15 * MB
    max_chunk_size = 150 * MB
    chunks = first_fit_decreasing(files, min_chunk_size, max_chunk_size)
    assert sorted(id(file) for file in files) == sorted(
        id(file) for chunk in chunks for file in chunk.files
    )
    for chunk in chunks:
        assert min_chunk_size <= chunk.size() <= max_chunk_size
    print(len(chunks), "chunks")
    print(sum(chunk.free for chunk in chunks) / MB, "MB free")


if __name__ == "__main__":
    for t in range(1000):
        test(150)
    test(10000)

【讨论】:

    猜你喜欢
    • 2023-01-17
    • 2020-06-01
    • 2013-12-11
    • 2020-03-20
    • 2010-10-11
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多