有效地解决这种递归关系。 [优于O(N ^ 2)]

时间:2012-10-06 10:42:01

标签: algorithm complexity-theory recurrence

我有一个复发关系,就像这样:

  

E(i,j)= A [i] + A [j] + E(i + 1,j-1)+ E(i + 2,j)+ E(i,j-2);如果我!= j

     

E(i,j)= A [i]; if(i == j)

  E(i,j)= 0;如果我&lt; 0或j <0 0

  A [i] 1&lt; = i&lt; = N;是简单的整数数组。

我想在时间复杂度上比O(N ^ 2)更好地求解E(1,N)。我想知道我们是否能找到一些这种复发的封闭形式公式,或者可能是一种计算E(1,N)值的聪明方法?

欢迎任何提示,
提前谢谢。

编辑:
实际问题是这样的:

  1. 我们有一个阵列A [],2个玩家轮流玩这个游戏。
  2. 玩家可以以0.5的概率选择最左边或最右边的数字并将其添加到他的分数中(如果数组中剩下单个元素,他只会选择该数字并且游戏结束)。
  3. 问题是找到Player1将达到的预期分数。

2 个答案:

答案 0 :(得分:3)

关于你的复发关系:

看起来有点困难,因为这篇文章表明,对于E(1,N)我们需要E(2,..)和E(3,..),其中每个都需要其他条目更高的“我”,等等。

现在,重新排列这些术语,使得我们将E-term与最高的“i”隔离开来(一般来说,一个好的想法是递归关系是要看一下隔离特定索引的不同安排 - 最高,最低的,中间的,...):

E(i + 2,j)= E(i,j)-E(i,j-2)-E(i + 1,j-1)-A(i)-A(j)

然后,将所有i向下移动2(只需重写公式)

E(i,j)= E(i-2,j)-E(i-2,j-2)-E(i-1,j-1)-A(i-2)-A( j)的

然后,对于你正在寻找的{i = 1,j = N},我们得到:

E(1,N)= E(-1,N)-E(-1,N-2)-E(0,N-1)-A(-1)-A(N)= -A (N),因为所有其他术语都是零。

(我当然假设,对于i = 0 / j = 0,E(i,j)和A(i)为零;当您仅为NEGATIVE指数指定零值时,您的规范可能不完整,但不是零指数。)

然后,关于你对基础案例的(编辑过的)描述 - 两个玩家轮流从A开始,任意地从左或右,直到A用尽:

从前面的结果来看,我不认为你的递归关系可能会描述基础游戏,给定结果-A(N)...因此,将该递归关系放在一边(无论如何,i = 1解决了它)。并了解游戏本身可能会产生什么样的关系。

[编辑后继续]

到目前为止,我还没有提出一些我可以以封闭形式投射的东西,即比处理某种递归关系更快的东西。因此,现在让我们写下我们如何以一种有助于计算的方式来描述游戏。

定义以下数量:

设X(i,k)是项目#i(阵列A)在转弯结束时仍然存在(即尚未被任何玩家占据)的概率#k(从两个玩家开始计数)。当然,k在我们的游戏中从1到N运行,我也是如此。出于验证目的,我们可能会注意到,对于所有i,X(i,N)必须为零:在游戏结束时,所有元素都已被采用。

如果我们可能需要(在公式评估中)X(i,k)超出“正常”范围的任何值,我们评估:

X(i,k)=1 for {1<=i<=N; k=0}: initially all elements in A are still there.
X(i,k)=0 whenever i<1 or i>N: no elements ever exist outside the (original) range of A.

接下来,让T(i,k)成为#i(由任何玩家)轮流#k准确地获取元素#i的概率。 它必须是0.5 *它是最左边元素(当前)的概率,这相当于说在PREVIOUS转弯结束时元素#(i-1)不存在,加上0.5 *它是概率最右边的元素(当前),这反过来相当于说在前一轮结束时元素#(i + 1)不存在,而所有这些元素必须乘以第一个元素#i本身存在的概率位:

T(i,k) = X(i,k-1) * ( (1-X(i-1,k-1)) + (1-X(i+1,k-1)) ) / 2

转向#k后元素#i仍然存在的概率X(i,k)是它在前一回合结束时存在的概率,减去转弯时#k的概率:

X(i,k) = X(i,k-1) - T(i,k)

元素#i与玩家#1结束的概率是T(i,k)的所有转弯k的总和,但仅计算HIS转弯。让我们用P(i,1)表示数量,其中1代表玩家#1。

P(i,1) = sum{ k=1,3,...: T(i,k) }

同样,对于玩家#2:

P(i,2) = sum{ k=2,4,...: T(i,k) }

球员#1的预期得分是总和S(1):

S(1) = sum( i=1..N: P(i,1)*A(i) }, and likewise for player #2: S(2) = sum( i=1..N: P(i,2)*A(i) }

看看上面的公式,我没有看到一种方法来避免时间上的O(N2)方法。内存使用量可以是O(N),因为我们可以继续运行总计并丢弃不再需要的旧“元素”数据。鉴于此 - 假设您没有处理过长的阵列A - 玩家将无法生存! - O(n2)时间表现在实践中不应该是这样的问题。

int N  = sizeof(A);

// note on the code below: we'll use i as an integer running over the elements in A, and k running over the turns that players make.
// while in human parlance we would have them (both) run from 1 to N, the zero-based arrays of C++ make it more convenient to let them 
// run from 0 to N-1.

// initialize the running totals P(i), the accumulated (over turns) probabilities that element #i winds up with player #1.
// if we ever need the same for player #2, it's values are of course 1-P (that is: at the end of the game).
double* P = new double[N];
for (int i=0; i<N; i++)
{
  P[i] = 0; // before we start, there's little chance that player #1 has already taken any element.
}
// initialize the existence-array for the elements.
int* X = new int[N];
for (int i=0; i<N; i++)
{
  X[i] = 1; // initially all elements exist, i.e. have not yet been taken by any player.
}
// declare an array for processing the probabilities that elements are taken at a particular turn.
double* T = new double[N];

// iterate over the turns.
for (int k=0; k<N; k++)
{
  // for each element, calculate the probability that it is taken NOW.
  // the current values of X - the existence array - refer to the (end of the) previous turn.
  for (int i=0; i<N; i++)
  {
    // note: take care of the boundaries i=0 and i=N-1.
    if (i == 0)
    {
      T[i] = X[i] * ( 2 - X[i+1] ) / 2;
    }
    else if (i == N-1)
    {
      T[i] = X[i] * ( 2 - X[i-1] ) / 2;
    }
    else
    {
      T[i] = X[i] * ( 2 - X[i-1] - X[i+1] ) / 2;
    }
  } // element i
  // with the take-probabilities for this turn in place, update P - only at odd turns (i.e. k=even): P is for player #1 only.
  if (k % 2 == 0)
  {
    for (int i=0; i<N; i++)
    {
      P[i] += T[i];
    }
  }
  // finally - in this turn - update the existence array.
  for (int i=0; i<N; i++)
  {
    X[i] -= T[i];
  }

} // turn k

// result: calculate the expected score for player #1.
double score = 0;
for (int i=0; i<N; i++)
{
  score += P[i] * A[i];
}

-

答案 1 :(得分:-1)

由于概率相等,这只是一个计数问题。

你能算出第k次转弯时选择A [j]的几率吗?