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

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::类似向量的类经过优化以容纳少量项目[重复]

    这个问题在这里已经有答案了 在程序的一个时间关键部分中 有一个类成员如下所示 std vector m vLinks 在分析过程中 我注意到该向量大约 99 98 的执行仅包含 0 或 1 个项目 然而 在极少数情况下 它可能会容纳更多 根
  • 确定向量中是否存在元素的最有效方法

    我有几种算法取决于确定元素是否存在于向量中的效率 在我看来 这 in 这相当于is element 应该是最有效的 因为它只返回一个布尔值 在测试了几种方法之后 令我惊讶的是 这些方法是迄今为止效率最低的 以下是我的分析 随着向量大小的增加
  • 在 C++ 中通过引用传递 std 算法谓词

    我正在尝试从 a 中删除元素std list并保留已删除元素的一些统计信息 为此 我使用列表中的remove if 函数 并且我有一个谓词 我想使用这个谓词来收集统计数据 这是谓词的代码 class TestPredicate privat
  • 优化 CSS 交付 - Google 的建议

    谷歌建议在 head 中使用非常重要的 CSS 内联 并在内部使用其他 CSS
  • URL路径相似度/字符串相似度算法

    我的问题是我需要比较 URL 路径并推断它们是否相似 下面我提供了要处理的示例数据 GROUP 1 robots txt GROUP 2 bot html GROUP 3 phpMyAdmin 2 5 6 rc1 scripts setup
  • 在常数空间中创建 1..N 的随机排列

    我正在寻找枚举固定空间中数字 1 N 的随机排列 这意味着我无法将所有数字存储在列表中 原因是 N 可能非常大 超过可用内存 我仍然希望能够一次遍历这样一个数字的排列 只访问每个数字一次 我知道对于某些 N 可以这样做 许多随机数生成器随机
  • 优化 LATERAL join 中的慢速聚合

    在我的 PostgreSQL 9 6 2 数据库中 我有一个查询 该查询根据一些股票数据构建计算字段表 它为表中的每一行计算 1 到 10 年的移动平均窗口 并将其用于周期性调整 具体来说 CAPE CAPB CAPC CAPS 和 CAP
  • make_shared<>() 中的 WKWYL 优化是否会给某些多线程应用程序带来惩罚?

    前几天我偶然看到这个非常有趣的演示 http channel9 msdn com Events GoingNative GoingNative 2012 STL11 Magic Secrets作者 Stephan T Lavavej 其中提
  • 需要一种将网络块范围折叠为超集范围列表的算法

    我的数学不及格 我需要一种有效的方法将网络范围缩小为超集 例如如果我输入 IP 范围列表 1 1 1 1至2 2 2 5 1 1 1 2至2 2 2 4 10 5 5 5至155 5 5 5 10 5 5 6至10 5 5 7 我想返回以下
  • 给定一个具有多个重复条目的数组,找到一个重复条目 O(N) 时间和常数空间

    我们得到了一个大小为 N 的数组 其中包含 0 到 N 2 范围内的整数 包括 0 和 N 2 该数组可以有多个重复的条目 我们需要在 O N 时间和常量空间中找到重复条目之一 我正在考虑取数组中所有条目的乘积和总和 以及 0 到 N 2
  • 什么是大O表示法?你用它吗? [复制]

    这个问题在这里已经有答案了 什么是大O表示法 你用它吗 我想我错过了这门大学课程 D 有人使用过它并给出一些现实生活中使用它的例子吗 也可以看看 八岁孩子的大O https stackoverflow com questions 10716
  • 实施二分查找有哪些陷阱? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 二分查找比看起来更难实现 虽然二分搜索的基本思想相对简单 但细节可能出人意料地棘手 Donald Knuth 新的二分搜索实现中最有可
  • 在java中使用BUBBLE SORT对二维字符串数组进行排序

    类似的问题已经被问过 但从来没有关于二维字符串数组 因此在尝试了很长时间之后我找不到我想要的 我正在尝试使用 BubbleSort 对 java 中的 2D 字符串数组进行排序 作为输入 我收到一个二维字符串数组 一个表 以及您应该排序的
  • 如何用约束标记一大组“传递群”?

    在 NealB解决方案之后进行编辑 与以下解决方案相比 NealB的解决方案非常非常快任何另一个 https stackoverflow com q 18033115 answers and 提出了关于 添加约束以提高性能 的新问题 Nea
  • 每个术语出现的次数

    我得到了一个数组a n 2 where n can be 10 5最大时有n个科目和n个学生 全部编号为 1 2 n a i 0 and a i 1 1 lt i lt n 表示在第 i 个科目中 所有来自a i 0 to a i 1 通过
  • gcc 与 clang:符号剥离

    gcc 和 AMD Open64 opencc 都有一个 s选项 剥离符号表和重定位信息 到目前为止我还没能在 Clang LLVM 中找到相同的选项 它存在吗 您可以使用stripbinutils 中的实用程序 实际上 llvm ld 有
  • 有没有时间复杂度为O(N)的排序算法?

    大多数排序算法的复杂度为 O NN 或 O NlogN 来实现结果 但是 对于特定的输入集 有些算法的复杂度为 O N 我想知道是否有一种排序算法在所有情况下都具有 O N 的复杂度 如果您只能比较 检查两个项目是否为 正在排序的值 那么您
  • 需要解释搜索最小大和的算法

    我正在解决 Codility 问题作为练习 但无法回答其中一个问题 我在互联网上找到了答案 但我不明白这个算法是如何工作的 有人可以引导我逐步完成它吗 这是问题 You are given integers K M and a non em
  • 平铺单纯形噪声?

    我 作为业余爱好者 对伪随机噪声生成很感兴趣 特别是 Perlin 和 Simplex 算法 Simplex 的优点是速度 尤其是在更高的维度上 但 Perlin 可以相对容易地平铺 我想知道是否有人知道平铺单纯形算法 固定维度就好 泛型更
  • scipy.optimize on pandas dataframe

    我试图搜索它 但结果很差 有人可以向我解释一下如何在 Pandas DataFrame 上执行 optimize minimize 以便最小化 DataFrame 中的类别和结果列之间的错误 考虑这个例子 import pandas as

随机推荐

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

    无限流 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 算法 后者