集合划分比差分获得更好的结果

2024-05-03

分区问题 https://en.wikipedia.org/wiki/Partition_problem已知是 NP 困难的。根据问题的特定实例,我们可以尝试动态规划或一些启发式方法,例如差分法(也称为 Karmarkar-Karp 算法)。

后者似乎对于具有大数字的实例非常有用(这使得动态编程变得棘手),但并不总是完美的。找到更好解决方案的有效方法是什么(随机、禁忌搜索、其他近似)?

PS:这个问题背后有一些故事。有一个挑战约翰尼去购物 http://www.spoj.com/problems/JOHNNY/自 2004 年 7 月起在 SPOJ 上提供。到目前为止,已经有 1087 位用户解决了该挑战,但其中只有 11 人的得分比正确的 Karmarkar-Karp 算法实现更好(按照当前的得分,Karmarkar-Karp 给出了 11.796614 分)。如何做得更好? (答案由最想要的已接受提交提供支持,但请不要透露您的代码。)


有许多论文描述了集合划分的各种高级算法。这里仅列出其中两个:

  • “一个完整的随时数字划分算法” http://www.sciencedirect.com/science/article/pii/S0004370298000861作者:理查德·E·科尔夫。
  • “子集和问题的高效全多项式近似方案” http://www.sciencedirect.com/science/article/pii/S0022000003000060汉斯·凯勒等人。

老实说,我不知道他们中的哪一个提供了更有效的解决方案。解决 SPOJ 问题可能不需要这些高级算法。科尔夫的论文还是很有用的。那里描述的算法非常简单(易于理解和实现)。他还概述了几种更简单的算法(在第 2 节中)。因此,如果您想了解 Horowitz-Sahni 或 Schroeppel-Shamir 方法(下面提到)的详细信息,您可以在 Korf 的论文中找到它们。此外(在第 8 节中)他写道,随机方法并不能保证足够好的解决方案。因此,通过爬山、模拟退火或禁忌搜索等方法不太可能获得显着的改进。

I tried several simple algorithms and their combinations to solve partitioning problems with size up to 10000, maximum value up to 1014, and time limit 4 sec. They were tested on random uniformly distributed numbers. And optimal solution was found for every problem instance I tried. For some problem instances optimality is guaranteed by algorithm, for others optimality is not 100% guaranteed, but probability of getting sub-optimal solution is very small.

对于尺寸最大为 4(左侧绿色区域)的 Karmarkar-Karp 算法始终给出最佳结果。

对于最大 54 的大小,暴力算法足够快(红色区域)。可以选择 Horowitz-Sahni 或 Schroeppel-Shamir 算法。我使用 Horowitz-Sahni 是因为它对于给定的限制似乎更有效。 Schroeppel-Shamir 使用的内存要少得多(所有内容都适合 L2 缓存),因此当其他 CPU 核心执行一些内存密集型任务或使用多个线程进行集合分区时,它可能更可取。或者在没有严格时间限制的情况下解决更大的问题(Horowitz-Sahni 只是耗尽内存)。

When size multiplied by sum of all values is less than 5*109 (blue area), dynamic programming approach is applicable. Border between brute force and dynamic programming areas on diagram shows where each algorithm performs better.

右侧的绿色区域是 Karmarkar-Karp 算法以几乎 100% 的概率给出最佳结果的地方。这里有如此多的完美分区选项(增量为 0 或 1),Karmarkar-Karp 算法几乎肯定会找到其中之一。可以发明 Karmarkar-Karp 总是给出次优结果的数据集。例如{17 13 10 10 10 ...}。如果将其乘以某个大数,KK 和 DP 都无法找到最优解。幸运的是,这样的数据集在实践中不太可能出现。但出题者可以添加这样的数据集,使比赛变得更加困难。在这种情况下,您可以选择一些高级算法以获得更好的结果(但仅限于图表上的灰色和右绿色区域)。

我尝试了两种方法来实现 Karmarkar-Karp 算法的优先级队列:使用最大堆和使用排序数组。排序数组选项在线性搜索中似乎稍快,而在二分搜索中则明显更快。

黄色区域是您可以在有保证的最佳结果(使用 DP)或仅具有高概率的最佳结果(使用 Karmarkar-Karp)之间进行选择的地方。

最后,灰色区域,其中任何简单算法本身都无法给出最佳结果。在这里,我们可以使用 Karmarkar-Karp 来预处理数据,直到它适用于 Horowitz-Sahni 或动态规划。在这个地方也有很多完美的分区选项,但比绿色区域少,所以Karmarkar-Karp本身有时可能会错过适当的分区。更新:正如@mhum 所指出的,没有必要实现动态编程算法来使事情正常工作。 Horowitz-Sahni 与 Karmarkar-Karp 预处理就足够了。但 Horowitz-Sahni 算法必须在上述时间限制内处理最大 54 的大小,以(几乎)保证最佳分区。所以C++或其他具有良好优化编译器和快速计算机的语言是优选的。

以下是我如何将 Karmarkar-Karp 与其他算法结合起来:

template<bool Preprocess = false>
i64 kk(const vector<i64>& values, i64 sum, Log& log)
{
    log.name("Karmarkar-Karp");
    vector<i64> pq(values.size() * 2);
    copy(begin(values), end(values), begin(pq) + values.size());
    sort(begin(pq) + values.size(), end(pq));
    auto first = end(pq);
    auto last = begin(pq) + values.size();

    while (first - last > 1)
    {
        if (Preprocess && first - last <= kHSLimit)
        {
            hs(last, first, sum, log);
            return 0;
        }
        if (Preprocess && static_cast<double>(first - last) * sum <= kDPLimit)
        {
            dp(last, first, sum, log);
            return 0;
        }
        const auto diff = *(first - 1) - *(first - 2);
        sum -= *(first - 2) * 2;
        first -= 2;
        const auto place = lower_bound(last, first, diff);
        --last;
        copy(last + 1, place, last);
        *(place - 1) = diff;
    }

    const auto result = (first - last)? *last: 0;
    log(result);
    return result;
}

完整 C++11 实现的链接。 http://ideone.com/0QYVDA该程序仅确定分区总和之间的差异,它不报告分区本身。Warning:如果您想在可用内存少于 1 Gb 的计算机上运行它,请减少kHSLimit持续的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

集合划分比差分获得更好的结果 的相关文章

  • 随机排列

    我无法找到一种随机洗牌元素的好方法std vector经过一些操作后 恢复原来的顺序 我知道这应该是一个相当简单的算法 但我想我太累了 由于我被迫使用自定义随机数生成器类 我想我不能使用std random shuffle 无论如何这没有帮
  • 在大文件中查找重复项

    我有一个非常大的文件 大约有 1500 万个条目 文件中的每一行都包含一个字符串 称为键 我需要使用 java 查找文件中的重复条目 我尝试使用哈希图并检测重复的条目 显然 这种方法向我抛出了 java lang OutOfMemoryEr
  • 如何计算一组字符串的最短唯一前缀?

    这是一个非常常见的算法命令行解析 给定一组预定义的长选项名称 计算唯一标识这些选项之一的最短前缀 例如 对于以下选项 help hostname portnumber name polymorphic 这将是输出 he ho por n p
  • 加权图的 BFS 算法 - 寻找最短距离

    我看过很多帖子 即 post1 https stackoverflow com questions 30409493 using bfs for weighted graphs post2 https cs stackexchange co
  • 算法 - 树中所有节点的最大距离

    所以 找到树中两个节点之间的最长路径相当容易 但我想要的是找到从节点出发的最长路径x到树中的另一个节点 对于所有x 这个问题也可以用以下方式表达 计算从给定的树中可以生成的所有有根树的高度 One way of course is to j
  • Python(和 Java)中最快的数据打包

    Sometimes http www codinghorror com blog 2009 01 the sad tragedy of micro optimization theater html our host is wrong na
  • 递归:n项级数之和

    需要递归函数 系列是 1 2 3 3 4 5 4 5 6 7 递归求 n 的级数之和 我无法想到应该在函数中传递哪些参数 我的方法 我认为我应该传递 n 要相乘的项数 但我无法想到的是我应该如何在同一个函数中 和 以及我的 return 语
  • 如何以最小化每个分区总和的最大值的方式对整数数组进行分区?

    输入是正整数或空整数的数组 A 和另一个整数 K 我们应该将 A 划分为 K 个连续元素块 我所说的 划分 是指 A 的每个元素都属于某个块 并且 2 个不同的块不包含任何共同元素 我们将块的总和定义为该块的元素的总和 目标是在 K 个块中
  • 字符串文字会被编译器优化吗?

    C 编译器或 NET CLR 是否对字符串文字 常量进行了任何巧妙的内存优化 我可以发誓我听说过 字符串内化 的概念 因此在程序中的任何两位代码中 文字 这是一个字符串 实际上会指代同一个对象 大概是安全的 对于字符串来说是这样的 不可变
  • javascript - 找到在一定限制下给出最大总和的子集(子集总和)

    我有一个包含一些整数值的数组 我需要获取它们的子集 该子集给出小于给定值的最大总和 假设我有这个数组 40 138 29 450 我想获得该数组的一个子集 使总和最大化 但低于用户给出的限制 比如说 250 在这种情况下 它应该返回 139
  • 我该如何解决? KnapSack - 值完全相同,但每个对象都有三个权重

    我在解决我的练习时遇到问题 我读到了动态规划和算法 我认为我的练习是 特定背包问题 我用暴力法解决了它 但我无法用动态规划解决它 我有一艘重300吨的船 背包 有些晶体本身含有 3 种物质 X Y Z 每种物质都有重量 并且所有晶体都具有相
  • 竞争性编码 - 以最低成本清除所有级别:未通过所有测试用例

    当我遇到这个问题时 我正在一个竞争性编码网站上解决问题 问题指出 游戏中有 N 个关卡和 M 种可用武器 等级编号从 0 到 N 1 武器编号从 0 到 M 1 您可以按任意顺序清除这些级别 在每个关卡中 需要这些 M 武器的某些子集才能通
  • 让 GCC 使用进位逻辑进行任意精度算术而不需要内联汇编?

    当使用任意精度算术 例如 512 位整数 时 有没有办法让 GCC 在不使用内联汇编的情况下使用 ADC 和类似指令 乍一看 GMP 的源代码表明他们只是为每个支持的平台提供了汇编实现 这是我编写的测试代码 它将命令行中的两个 128 位数
  • 优化 tribool 数组的空间

    让我从一些背景开始 通过 tribool 我理解一个可以保存以下值之一的变量 true false or null 有问题复制整数数组与布尔指针数组 https stackoverflow com questions 4350041 cop
  • 如何计算加权平均值?

    我的语言是PHP 但是算法应该是相当通用的 我有一个关联数组 比方说 评级和评级次数 ratings array 1 gt 1 2 gt 3 3 gt 6 4 gt 3 5 gt 3 这相当于 1 2 2 2 3 3 3 3 3 3 4 4
  • 将 javascript 合并到一个文件中

    最近阅读了雅虎的网络优化技巧并使用 YSlow 我在我的一个网站上实现了他们的一些想法http www gwynfryncottages com http www gwynfryncottages com你可以在这里看到该文件http ww
  • 使用向量的 merge_sort 在少于 9 个输入的情况下效果很好

    不知何故 我使用向量实现了合并排序 问题是 它可以在少于 9 个输入的情况下正常工作 但在有 9 个或更多输入的情况下 它会执行一些我不明白的操作 如下所示 Input 5 4 3 2 1 6 5 4 3 2 1 9 8 7 6 5 4 3
  • 以编程方式分解大量数字

    好吧 所以我有一个巨大的数字f 实际上 这个数字只有 100 多位数字长 我知道这些因子的大小大致相同 如果我的资源和时间有限 我应该使用什么语言和算法 我包括在限制时间内编写算法的时间长度 想法 编辑 我所说的有限是指在尽可能短的时间内
  • 循环中的递归算法复杂度(运行时间)

    我想了解您对如何检测以下递归算法的 T n 运行时间 的意见 Charm 是一种用于发现事务数据库中频繁闭项集的算法 频繁闭项集列表是在一组交易 tids 中多次出现的频繁项 例如面包和牛奶是经常一起购买的物品 它们是通过将索引为 i 的当
  • 缓存感知树的实现

    I have a tree where every node may have 0 to N children 用例是以下查询 给定指向两个节点的指针 这些节点是否位于树的同一分支内 Examples q 2 7 gt true q 5 4

随机推荐

  • 在自己的定义中使用变量?

    无限流 val ones Stream Int Stream cons 1 ones 一个值怎么可能在它自己的声明中使用呢 看起来这应该会产生编译器错误 但它确实有效 它并不总是递归定义 这实际上有效并产生 1 val a Int a 1
  • Web.config 身份验证错误

    我使用的是SQLServer2005和VS2008 我在 web config 中的连接字符串是 add name library connectionString Data source KMT Initial Catalog Libra
  • RxJS Angular2 在 Observable.forkjoin 中处理 404

    我目前正在链接一堆 http 请求 但是在订阅之前我无法处理 404 错误 My code 在模板中 service getData subscribe data gt this items data err gt console log
  • 通过 https 安全登录后,Weblogic 应用程序切换回 http

    我已在 Weblogic 9 2 MP3 上成功配置 SSL 我能够使用 https 安全地登录应用程序 并继续使用 https 协议处理应用程序 当用户访问提供以下 URL 的应用程序时 情况就是如此 https servername 7
  • 一种父子关系级联软删除的方法

    我有一个简单的架构 其中使用软删除 这就是它的设计方式并且无法更改 有两个表参与该架构 Company id is deleted and Employee id company id is deleted where company id
  • 从文件导入变量创建变量的副本

    If I from file import variable and the varable在模块文件中更改 variables 值未更新 如果我 import file 变量file variable已更新 有没有一种方法可以有选择地从模
  • 如何从命令行运行 spock 测试?

    我已经检查过这个链接 https gist github com ysb33r 5825457 https gist github com ysb33r 5825457 似乎可以这样运行 groovyc groovy java cp gra
  • 所有AJAX请求完成时的JQuery调用函数

    我的问题是问题的变体here https stackoverflow com questions 970967 jquery ajax call function when all requests are complete 然而 有两点不
  • MPAndroidChart BarChart xValues 问题

    我注意到有一个问题BarChart of MPAndroidChart并需要修复 首先是我的代码 this barChart BarChart view findViewById R id bar fragment bar chart th
  • AutoCAD 插件开发示例

    我对开发 AutoCAD 插件感兴趣 并试图了解几种不同类型的 AutoCAD 插件文件之间的关系 随 AutoCAD 插件一起提供的托管 DLL ARX 文件 https fileinfo com extension arx附带 Auto
  • 如何在 SQLite 中插入换行符(“\n”)?

    在尝试插入类似以下内容时 Hello nWorld SQLite 抛出类似以下的错误 消息 无法识别的令牌 Hello 还有一些其他错误 即使我将上面的字符串转换为 Hello nWorld or Hello n World 这些转义字符序
  • 退格事件麻烦

    我在第 1 页有一个事件侦听器 window addEventListener keydown 这给我带来了问题 即第 1 页对话框中的另一个事件侦听器 keydown 与窗口事件侦听器发生冲突 有两个事件监听器 对话框事件监听器 页面事件
  • 使用畸变从图像平面计算相机矢量

    我正在尝试使用相机模型来重建可以使用某些相机及其 外部 内部 参数拍摄的图像 这一点我没有任何问题 现在我想添加扭曲 正如它们中所描述的那样OpenCV https docs opencv org 4 x dc dbb tutorial p
  • React TypeScript - 将动态泛型类型传递到forwardRef组件中

    我的问题的核心 const FinalComponent
  • 机器和管道(或其他类似的库)之间的概念区别是什么?

    我想学习这个概念 以便我能够理解和使用诸如machines http hackage haskell org package machines 我试着跟随R nar Bjarnason 关于机器的演讲 https dl dropbox co
  • 授予对视图的 SELECT 权限,但不授予对基础对象的 SELECT 权限

    我经常读到 视图的目的之一是安全性 允许某些用户访问基础表 而其他用户仅访问派生视图 考虑到这一点 我设计了几个向外部用户提供受限数据集的视图 一切都很好 但在实践中这是行不通的 我授予后SELECT对视图的权限 除非我授予 否则用户无法访
  • XPath 直到下一个标签

    与之前在这里问过的其他人类似的问题 但由于我不知道如何应用这些建议 所以我需要一些帮助 我想找到一个 html 文档的节点 其结构如下 摘录 可能有所不同 h2 My title 1 h2 h3 Sub heading h3 p span
  • Laravel Schema onDelete 设置为 null

    无法弄清楚如何在 Laravel 中的表上设置正确的 onDelete 约束 我正在使用 SqLite table gt gt onDelete cascade works table gt gt onDelete null set nul
  • .Net 如何创建一个在进程的所有AppDomain之间共享的自定义ThreadPool?

    我制作了一个针对我的特定需求进行优化的自定义线程池 但是 当进程中有多个 AppDomain 时 CLR ThreadPool 能够在所有 AppDomain 之间共享 我希望能够重现这种行为 这可以使用 MarshalByRefObjec
  • 集合划分比差分获得更好的结果

    分区问题 https en wikipedia org wiki Partition problem已知是 NP 困难的 根据问题的特定实例 我们可以尝试动态规划或一些启发式方法 例如差分法 也称为 Karmarkar Karp 算法 后者