迭代最大化算法

时间:2015-12-14 01:35:00

标签: java c++ algorithm

以下是我目前要解决的问题。

有一个名为T的最大值。然后有两个子值A和B,它们是1< = A,B< = T.在每一轮中,你可以选择A或B来添加到你的和。你也可以选择只在其中一轮完成一半的总和。任何一轮都不能超过T.给定无限次数,你可以获得的最大金额是多少。

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

解决方案:我们首先取B,然后取一半的总和3.然后我们加A并得到8.所以最大可能是8.

我提出的迭代思想是:它基本上是一个树结构,你可以保持分支并尝试构建旧的和。我无法找出最大化公式。

是否存在可以快速运行的蛮力解决方案还是有一些优雅的公式?

限制:1&lt; = A,B&lt; = T.T <= 5,000,000。

编辑:当你分割时,你向下舍入总和(即5/2变为2)。

4 个答案:

答案 0 :(得分:4)

可以将问题视为具有T + 1个节点的有向图。想象一下,我们有T + 1个从0到T的节点,如果出现以下情况,我们就有从节点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)

答案 1 :(得分:1)

按照我的理解总结你的问题设置(在你可以除以2的约束下不超过一次):

  1. 根据需要添加AB次数(包括每次0)
  2. 除以2,向下舍入
  3. 根据需要多次添加AB
  4. 目标是获得尽可能大的总和,但要遵守算法任何步骤后总和不超过T的约束。

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

    • a1:我们在除以2之前添加A的次数
    • b1:我们在除以2之前添加B的次数
    • s1floor((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"
    

答案 2 :(得分:0)

我们可以用这种方式描述问题:

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))

可以轻松地为任何相应的s

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

E.g:

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&#39;匹配约束如下:r' = r + B / gcd(A , B) * nAB可以通过此方法进行交换,从而可以使用较小的输入值B进一步优化。

在算法中将变量除以2时的值的舍入应该只会导致小问题,这很容易修复。

答案 3 :(得分:0)

我会使用一些数学方法。

恢复:

你应该能够用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

一些解释:

使用规则:A p + B q(不除以2)

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

示例:A = 11,B = 17

2如果A = C x,并且B = C y,x,y素数在一起(如10和21),则可以得到每个C倍数,然后max = C下面的最大倍数T:圆形(T / C)* C

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

使用规则:你可以除以2

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

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

4 - 否则,你必须找到A,B,圆(A / 2),圆(B / 2)的最大dividor(最高公因子),称之为D,max = D以下D的最大倍数:圆(T / D)* D. 由于A和圆(A / 2)是素数(B和圆(B / 2)的同义词),然后你可以得到max = T,如案例1 - 警告:我不确定你是否永远不会去过去T.检查