【问题标题】:How do i solve this in a faster and more accurate way?如何以更快、更准确的方式解决这个问题?
【发布时间】:2012-12-18 14:00:36
【问题描述】:

问题来了:

拉穆是个懒惰的农民。他从父亲那里继承了一个相当大的农场和一所漂亮的房子。拉木将农田出租给他人,收入颇丰。他的父亲曾经在家里养一头水牛并卖掉它的牛奶,但水牛在他父亲死后几天就死了。
Ramu 也想从水牛身上赚点钱,但方式完全不同。他决定他的未来在于投机水牛。在他村里的市场上,每天都有水牛买卖。价格在一年中波动,但在任何一天价格始终相同。
他决定在价格低的时候买水牛,在价格高的时候卖掉它们,在这个过程中积累大量的财富。不幸的是,他的房子只能容纳一头水牛,因此他在任何时候最多只能拥有一头水牛。
在他进入水牛市场之前,他决定检查一下过去几天水牛价格的变化,并确定他可以赚取的最大利润。假设,过去 10 天一头水牛的价格变化为

10 12 8 11 11 10 12 15 13 10

Ramu 是个懒惰的家伙,他估计在过去的 10 天里他最多愿意去市场 5 次(每次要么买卖一头水牛)。鉴于此,他可以赚取的最大利润是 9 卢比。为此,他在第 1 天买了一头水牛,第 2 天卖出,第 3 天再买一头,第 8 天卖出。如果他不那么懒惰,愿意去市场 6 次,那么他本可以赚更多的钱。他本可以在第 1 天买入,在第 2 天卖出,在第 3 天买入,在第 4 天卖出,在第 6 天买入并在第 8 天卖出,以赚取 10 卢比的利润。
你的任务是帮助 Ramu 计算他通过投机水牛可以赚取的最大金额,给定一段时期内每日水牛价格的历史记录,以及 Ramu 在此期间愿意进入市场的次数的限制。

输入格式
输入的第一行包含两个整数 N 和 K,其中 N 是价格数据可用的天数,K 是 Ramu 愿意访问牛市的最大次数。接下来的 N 行(第 2、3、...、N+1 行)每行都包含一个正整数。第 i+1 行的整数,1 ≤ i ≤ N,表示一头水牛在第 i 天的价格。

输出格式
一个非负整数,表示如果 Ramu 最多进行 K 次进入市场,他可以赚取的最大利润。
您可以假设 N ≤ 400 和 K ≤ 400。
时间限制 = 3 秒。

如果我们没有约束 k,我们可以使用贪心方法解决这个问题,

 while c < N
   i = c
   while price[day i] > price[day i+1] increment i;
   j = i+1
   while price[day j] < price[day j+1] increment j;
   add price[day j] - price[day i] to out profit
   c = j+1

但我们不能在这里使用它,因为是否在特定日期访问取决于我们访问了多少天。 这是我尝试过的

 //Store all the pairs generated in the previous algorithm in a linked list L, each
 //element has two attributes buy,sell
 while length of L > k/2
       find an element i in the list such the (L[i].sell- L[i-1].buy) - 
       (L[i-1].buy - L[i-1].sell) - (L[i].buy - L[i].sell) is maximized.
       Then set L[i-1].sell to L[i].sell and delete i from the list

这是一个在线法官的问题,当我提交它时,我的一些测试用例超出了时间限制,一些测试用例的答案错误,只对一个测试用例进行了纠正。

我的方法有什么问题,它怎么会很慢,因为它需要大约 O(NK) 时间,其中 N 和 K 如何改进我的算法以正确解决问题?

编辑:这不是作业,我在这里发现了这个问题:http://opc.iarcs.org.in/index.php/problems/BUFFALOES

【问题讨论】:

  • @niklas-r 这不是作业我在网上的评委上读到这个问题:opc.iarcs.org.in/index.php/problems/BUFFALOES
  • @NiklasR 'homework' 是一个已弃用的标签,即使它不是你也无权添加它。
  • 提示:最好的解决方案只需要 1 毫秒

标签: c algorithm dynamic-programming greedy


【解决方案1】:

我没有仔细分析过,但在我看来,你对懒惰的农民的想法有点太贪婪了。我很难想象你的链表,或者它上面的操作。

我认为考虑这个问题的一个好方法是,不用担心效率,将其转换为图表,其中每一天都是图表中的一个节点。

如果我们有一位勤奋的交易者愿意尽可能频繁地访问市场,那么它看起来像下面的图 1,我在您的示例中的前几天在其中进行了展示。图中从每天到每以后天绘制弧线,弧线的权重如下:

  • 连续的日子必须有一条弧线——要么用第二天买入然后卖出的利润加权,或者(如果这样的活动是亏损的话)加权为零
  • 仅当利润为正时,非连续天数才需要弧线。 (虽然您可以为非盈利货币对绘制零权重弧线,但我已将它们隐藏在下方,以便图表可读。)

此图需要 O(N^2) 比较/减法来创建。一旦有了这张图,为农夫找到最佳计划就相当于通过该图找到最长的路径(例如,从第一天到最后一天的弧值总和最大的路径)。通常,找到通过图的最长路径是 NP-Complete,但在这种情况下,我们有一个有向无环图——您可以简单地否定所有边权重,并使用 Dijkstra 算法在多项式时间内找到最短路径。

要对付懒惰的农夫,您需要调整此图结构,使其“计算”非零弧。我们通过使图表更大来做到这一点。大了很多。如果农民愿意去市场进行 k 次旅行,他有 floor(k/2) 个买/卖对。让我们称这个数字为 X,然后每 X+1 次绘制图中的节点。

同一行中的每个连续弧(无论当天的利润如何)的权重为 0。正长度的弧被重定向到下面的行。图 2 显示了如果农民愿意去市场 4 次,总共有 2 个买入/卖出机会,情况会怎样。您还可以从每行的末尾免费添加一个虚拟“终端节点”。

您可以看到,这通过确保每个获利机会逐行移动来“计算”利润弧,并且永远不会有机会多次使用同一行。同样,您可以找到找到正确答案的最长路径;并且该图再次是有向无环的,因此可以将其转换为最短路径问题并在多项式时间内求解。

坏消息是,节点数和弧数大幅增加。如果 k=N,你可能有 O(N^2) 而不是 N 个节点。同样,不是 O(N^2) 弧,而是 O(N^3)。

你可以通过将问题转换为网格来在时间和空间上做得更好,类似于最长公共子序列问题,但这至少说明了问题的结构。

【讨论】:

  • (作为旁注,这个问题被标记为“动态规划”,就我而言,Dijkstra 的最短路径算法符合动态规划的条件。)
  • 非常感谢您的回答,我还找到了另一种算法,类似于递归,但它消除了一些可能性,我终于被接受了。
  • 你愿意分享算法吗?
猜你喜欢
  • 2020-09-26
  • 2012-11-06
  • 2020-03-16
  • 2020-08-31
  • 2022-11-29
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多