【问题标题】:Iterative Maximization Algorithm迭代最大化算法
【发布时间】:2015-12-14 01:35:00
【问题描述】:

这是我目前正在尝试解决的问题。

有一个最大值称为 T。然后有两个子值 A 和 B,它们是 1

这是一个例子: T = 8 A = 5, B = 6

解:我们先取B,然后取一半的和得到3。然后我们加A得到8。所以最大可能是8。

我提出的迭代想法是:它基本上是一个树形结构,您可以在其中不断分支并尝试构建较旧的总和。我在尝试找出最大化公式时遇到了麻烦。

是否有可以快速运行的蛮力解决方案,或者是否有一些优雅的公式?

限制:1

编辑:除法时,将总和向下舍入(即 5/2 变为 2)。

【问题讨论】:

  • 除了大于等于1之外,A还有其他限制吗?
  • 限制如下。 1
  • A,B,T 只是整数还是浮点数?如果它是整数,你如何舍入 5/2 ?
  • 你把除法四舍五入。忘记说了。

标签: java c++ algorithm


【解决方案1】:

可以将问题视为具有T + 1 节点的有向图。假设我们有从 0 到 TT + 1 节点,并且我们有从节点 x 到节点 y 的边,如果:

  • x + A = y

  • x + B = y

  • x/2 = y

所以,为了回答这个问题,我们需要在图中进行搜索,声明点是节点0

我们可以通过breath first searchdepth first search 来解决问题。

更新:因为我们只能做一次划分,所以我们必须在图中添加另一个状态,即isDivided。但是,解决这个问题的方法并没有改变。

我将使用 BFS 实现来演示解决方案,DFS 非常相似。

class State{
    int node, isDivided;
}

boolean[][]visited = new boolean[2][T + 1];
Queue<State> q = new LinkedList();
q.add(new State(0, 0));//Start at node 0, and haven't use division
visited[0][0] = true;
int result = 0;
while(!q.isEmpty()){
    State state = q.deque();
    result = max(state.node, result);
    if(state.node + A <= T && !visited[state.isDivided][state.node + A]){
          q.add(new State(node + A , state.isDivided));
          visited[state.isDivided][node + A] = true;
    }
    if(node + B <= T && !visited[state.isDivided][node + B]){
          q.add(new State(node + B, state.isDivided));
          visited[state.isDivided][node + B] = true;
    }
    if(state.isDivided == 0 && !visited[state.isDivided][node/2]){
          q.add(new State(node/2, 1));
          visited[state.isDivided][node/2] = true;
    }
}
return result;

时间复杂度为 O(n)

【讨论】:

  • 您最多只能分割一次。这还能用吗?
  • @user3188300 结果被添加到队列中,所以它不仅被分割一次。假设您将 5 添加到队列中,那么下一步,我们将 (5/2 = 2) 添加到队列中。之后的一些步骤,我们将处理 2(它已经在队列中),然后我们将 (2/2 = 1) 添加到队列中。
  • 我要问的是,在问题陈述中,总体上只允许除以 2 一次。你不能一直除以 2。例如,一旦我去 5/2 = 2。我不能再除此总和。
  • @user3188300 我明白了,所以实际上,我们需要在解决方案中添加另一个维度,即isDivided。解决它的方法并没有太大的不同。等待我的编辑:)
  • 所以我们有两张图,一张表示已划分的情况,另一张表示尚未划分的情况?
【解决方案2】:

按照我的理解总结您的问题设置(在您不能多次除以二的约束下):

  1. 添加AB 任意次数(包括每个0)
  2. 除以 2,四舍五入
  3. 随意添加AB

目标是获得最大可能的总和,条件是在算法的任何一步之后总和不超过T

这可以在一个 5 变量整数程序中巧妙地捕捉到。这五个变量是:

  • a1:除以2之前我们加A的次数
  • b1:除以2之前我们加B的次数
  • s1:floor((A*a1+B*b1)/2),第二步后的总和
  • a2:除以2后我们添加A的次数
  • b2:除以2后我们加上B的次数

最终总和为s1+A*a2+B*b2,约束不超过T;这是我们寻求最大化的。所有五个决策变量都必须是非负整数。

这个整数程序可以很容易地通过整数规划求解器求解到最优。例如,这里是你将如何使用 R 中的 lpSolve 包解决它:

library(lpSolve)
get.vals <- function(A, B, T) {
  sol <- lp(direction = "max",
            objective.in = c(0, 0, 1, A, B),
            const.mat = rbind(c(A, B, 0, 0, 0), c(0, 0, 1, A, B), c(-A, -B, 2, 0, 0), c(-A, -B, 2, 0, 0)),
            const.dir = c("<=", "<=", "<=", ">="),
            const.rhs = c(T, T, 0, -1),
            all.int = TRUE)$solution
  print(paste("Add", A, "a total of", sol[1], "times and add", B, "a total of", sol[2], "times for sum", A*sol[1]+B*sol[2]))
  print(paste("Divide by 2, yielding value", sol[3]))
  print(paste("Add", A, "a total of", sol[4], "times and add", B, "a total of", sol[5], "times for sum", sol[3]+A*sol[4]+B*sol[5]))
}

现在我们可以计算如何在不超过 T 的情况下获得尽可能高的总和:

get.vals(5, 6, 8)
# [1] "Add 5 a total of 1 times and add 6 a total of 0 times for sum 5"
# [1] "Divide by 2, yielding value 2"
# [1] "Add 5 a total of 0 times and add 6 a total of 1 times for sum 8"
get.vals(17, 46, 5000000)
# [1] "Add 17 a total of 93 times and add 46 a total of 0 times for sum 1581"
# [1] "Divide by 2, yielding value 790"
# [1] "Add 17 a total of 294063 times and add 46 a total of 3 times for sum 4999999"

【讨论】:

    【解决方案3】:

    我将使用一些数学方法。

    简历:

    您应该能够用 A、B、T 计算最大值,无需迭代(仅用于获得 A/B HCD),对于 T,而不是小。

    • 如果 A 或 B 是奇数,max = T(有保留,我不确定你永远不会超过 T:见下文)。

    • 如果 A B 是偶数,则取 C 作为最大公因数。那么max = round (T/C*2) *C/2 = C/2 的最大倍数低于或等于T

    一些解释:

    使用规则:Ap+Bq(不除以 2)

    1 假设 A 和 B 是素数,那么你可以得到你想要的每个整数,在小数之后。那么max=T

    示例:A=11,B=17

    2 如果 A=Cx, 和 B=Cy, x,y 素数在一起(如 10 和 21),可以得到每个 C 的倍数,那么 max= 下面 C 的最大倍数T: 圆(T/C)*C

    示例:A=33,B=51 (C=3)

    根据规则:你可以除以 2

    3 - 如果 C 是偶数(即 A 和 B 可以被 2 整除): max= T 以下 C/2 的倍数:round(T/C*2)*C/2

    示例:A=22,B=34 (C=2)

    4 - 否则,你必须找到A,B,round(A / 2),round(B / 2)的最大除数(最大公因数),称之为D,max = D在T以下的最大倍数: 圆形(T/D)*D 由于 A 和轮 (A/2) 是素数(B 和轮 (B/2) 同上),那么你可以得到 max = T,如案例 1 - 警告:我不确定你是否永远不会超过 T . 检查

    【讨论】:

      【解决方案4】:

      我们也可以这样描述问题:

      f(A , B) = (A * n + B * m) / 2 + (A * x + B * y) 
               = A * (n * 0.5 + x) + B * (m * 0.5 + y) =
               = A * p + B * q
      find N: N = f(A , B) and N <= T such that no M: M > N satisfying  
      the condition exists.
      

      没有被二除的情况可以很容易地用n = m = 0表示,因此也可以用f覆盖。

      ny 可以是匹配p = n * 0.5 + y 的任意值(q 和相关值相同)。请注意,f 中显示了多个有效的解决方案。

      T >= A * p + B * q
      r = p * 2, s = q * 2
      find integral numbers r, s satisfying the condition
      T >= A * r / 2 + B * s / 2
      
      simplify:
      T * 2 / B >= A / B * r + s
      

      因此我们知道:

      (T / B * 2) mod 1 - (A / B * r) mod 1 is minimal and >= 0 for the optimal solution
      T * 2 / A >= r >= 0 are the upper and lower bounds for r
      (A / B * r) mod 1 = 0, if r = B / gcd(A , B) * n, where n is an integral number
      

      使用这些约束来查找 r 现在变成了一项简单的任务,使用二分查找。对此可能有更有效的方法,但 O(log B) 应该为此目的:

          Apply a simple binary-search to find the matching value  
          in the range [0 , min(T * 2 / A , B / gcd(A , B))
      

      对于任何对应的r,可以轻松找到s

      s = roundDown(T * 2 / B - A * r / B)
      

      例如:

      A = 5
      B = 6
      T = 8
      
      gcd(A , B) = 1
      search-range = [0 , 6)
      (T / B * 2) mod 1 = 4 / 6
      
      (A / B * r) mod 1 = 
          r = 3: 3 / 6 => too small --> decrease r
          r = 1: 5 / 6 => too great --> increase r
          r = 2: 4 / 6 => optimal solution, r is found
      
      r = 2
      s = roundDown(T * 2 / B - A * r / B) = roundDown(3.2 - 1.66) = 1
      
      p = r / 2 = 1 = 1 + 0 = 2 * 0.5  --> n = 1 y = 0 or n = 2 y = 0
      q = s / 2 = 0.5                  --> n = 0.5 y = 0
      
      8 >= 5 * 1 + 5 * 0.5 * 0 + 0 * 6 + 1 * 0.5 * 6 = 5 + 3 
         = 5 * 0 + 5 * 0.5 * 2 + 0 * 6 + 1 * 0.5 * 6 = 5 + 3
      

      这种方法的优势:我们可以在O(log B)找到所有解决方案: 如果找到 r 的值,则与约束匹配的所有其他值 r' 如下所示:r' = r + B / gcd(A , B) * nAB 在这种方法中是可交换的,允许通过使用较小的输入值作为 B 来进一步优化。

      在算法中将变量除以 2 时对值进行四舍五入只会导致小问题,这很容易解决。

      【讨论】:

      • 一个好方法。顺便说一句,你如何表示在整个迭代过程中的任何时候,总和不能超过 T?我认为它应该类似于A*m + B*n &lt;= T,但我在您的回答中看不到这一点。或许你可以澄清一下?
      • @justhalf 是重新定义问题,然后是计算(T &gt;= A * p + B * q 例如,示例的第 4 行)?
      • 我明白了,也许您也可以将其包含在问题重新描述中。
      • 看起来不错,你能提供一些关于你的近似方法的文件吗:)?
      • @PhamTrung 实际上我在近似值上犯了一个错误——需要一点睡眠。它比我想象的要复杂得多。我会编辑帖子。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-09
      • 1970-01-01
      • 1970-01-01
      • 2017-06-29
      • 2011-12-16
      • 1970-01-01
      相关资源
      最近更新 更多