任何人都可以解释这个memoization /动态编程概率/谜题的解决方案吗?

时间:2011-11-16 10:38:24

标签: c algorithm dynamic-programming memoization

这是问题陈述:

  

这是一款双人游戏。最初在数组中有n个整数,玩家A和B有机会交替使用它们。每个玩家可以从阵列的左端或右端获取一个或多个数字,但一次不能从两端获取。在他那段时间里,他可以随心所欲地连续数字。当玩家从阵列中取出所有数字时,游戏结束。每个球员的得分是通过他所取得的数字的总和来计算的。每个玩家都试图从其他玩家获得更多积分。如果两个玩家都发挥最佳状态并且玩家A开始游戏,则玩家A获得的积分比玩家B多多少?

     

输入

     

输入包含许多案例。每个案例都以一行指定整数n (0 < n ≤100),即数组中的元素数。之后,为游戏提供n个数字。输入由n=0

的行终止      

输出

     

对于每个测试用例,打印一个数字,表示第一个玩家在以最佳方式玩游戏后获得的最大差异。

Sample Input                                Output for Sample Input

4

4 -10 -20 7                                 7

4

1 2 3 4                                     10

5

4 -10 -20 7 19                              12

0

这是这个问题的解决方案。

#include<stdio.h>
#include<stdlib.h>
#define maxn 103

//typedef long long bg;
typedef long bg;

bg Table[maxn][maxn];
bg Seq[maxn];
bool Flag[maxn][maxn];
bg N;

bg Sum(int l, int r) {
    int i, sum = 0;
    for (i = l; i <= r; i++)
        sum += Seq[i];
    return sum;
}

bg Recur(int L, int R) {
    bg max, i, d, k;
    if (L == R)
        return Seq[L];
    if (Flag[L][R])
        return Table[L][R];
    max = Sum(L, R);
    d = Seq[L];
    for (i = L + 1; i <= R; i++) {
        k = Recur(i, R);
        if ((d - k) > max)
            max = d - k;
        d += Seq[i];
    }
    d = Seq[R];
    for (i = R - 1; i >= L; i--) {
        k = Recur(L, i);
        if ((d - k) > max)
            max = d - k;
        d += Seq[i];
    }
    Flag[L][R] = true;
    Table[L][R] = max;
    return max;
}

void Cal() {
    bg max, i, d, k;
    max = Sum(1, N);
    d = Seq[1];
    for (i = 2; i <= N; i++) {
        k = Recur(i, N);
        if ((d - k) > max)
            max = d - k;
        d += Seq[i];
    }
    d = Seq[N];
    for (i = N - 1; i >= 1; i--) {
        k = Recur(1, i);
        if ((d - k) > max)
            max = d - k;
        d += Seq[i];
    }
    printf("%ld\n", max);
}

void Reset() {
    for (int i = 1; i <= 100; i++) {
        for (int j = 1; j <= 100; j++)
            Flag[i][j] = false;
    }
}
int main() {
    //freopen("in.txt", "r", stdin);
    int i;
    while (scanf("%ld", &N) && N) {
        for (i = 1; i <= N; i++)
            scanf("%ld", &Seq[i]);
        Cal();
        Reset();
    }
    return 0;
}

我做了调试,但发现很难理解解决方案。

任何人都可以解释这个问题的代码或解决方案。或者,任何人都可以发布代码来解决动态编程而不是递归的问题吗?

1 个答案:

答案 0 :(得分:1)

此处的状态为Table[left][right],如果您的序列包含leftright之间的元素,则表示最佳解决方案。在每个步骤中尝试每个可能的移动 - 从左侧获取N元素或从右侧获取N元素,其中N在1right - left之间。

Example:
4 -10 -20 7

从左边开始:

  

表[1] [4] = max(sum(1,1) - 表[2] [4],sum(1,2) - 表[3] [4],   sum(1,3) - 表[4] [4],sum(1,4))。

从右边开始:

  

表[1] [4] = max(sum(4,4) - 表[1] [3],sum(3,4) - 表[1] [2],   sum(2,4) - 表[1] [1],sum(1,4))。

sum(L, R)LR之间的数组之和。我因为下一个对手转而减去。