我有一个复发关系,就像这样:
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)值的聪明方法?
欢迎任何提示,
提前谢谢。
编辑:
实际问题是这样的:
答案 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]的几率吗?