你可以通过动态规划来解决它。
让a 表示输入元素n=length(a)。
令f[i,j]表示取前i个硬币和最后(nj)个硬币时S(Pl1)-S(Pl2)的最大结果,g[i,j]表示S(Pl1)-S(Pl2)的最小结果.
f[i,j] = max{g[i+1,j]+a[i], g[i+2,j]+a[i]+a[i+1], g[i+1,j-1]+a[i]+a[j], g[i,j-2]+a[j]+a[j-1], g[i,j-1]+a[j]}
g[i,j] = min{f[i+1,j]-a[i], f[i+2,j]-a[i]-a[i+1], ...}
这个想法是剩余硬币的最佳策略独立于其他硬币的获取方式。
函数可以通过将g[i,j]替换为-f[i,j]来简化,因为g和f之间的唯一区别是取币的顺序。
这里是幼稚的 C 实现:
#include <stdio.h>
#include <string.h>
typedef struct record{
int lDelta, rDelta;
int score;
};
void checkAndUpdate(int value, int* addr, struct record *rec, int ld, int rd, int s) {
if (value > *addr) {
*addr = value;
rec->lDelta = ld;
rec->rDelta = rd;
rec->score = s;
}
};
int main() {
int n;
scanf("%d", &n);
int a[n];
for (int i = 0; i < n; ++i)
scanf("%d", a + i);
int f[n][n];
memset(f, 128, sizeof(f));
struct record r[n][n];
for (int i = 0; i < n; ++i) {
if (i > 0)
f[i][i-1] = 0;
checkAndUpdate(a[i], &f[i][i], &r[i][i], 1, 0, a[i]);
}
for (int l = 1; l < n; ++l) {
for (int i = 0; i + l < n; ++i) {
checkAndUpdate(-f[i + 1][i + l] + a[i], &f[i][i + l], &r[i][i + l], 1, 0, a[i]);
checkAndUpdate(-f[i + 2][i + l] + a[i] + a[i + 1], &f[i][i + l], &r[i][i + l], 2, 0, a[i] + a[i + 1]);
checkAndUpdate(-f[i + 1][i + l - 1] + a[i] + a[i + l], &f[i][i + l], &r[i][i + l], 1, 1, a[i] + a[i + l]);
checkAndUpdate(-f[i][i + l - 2] + a[i + l - 1] + a[i + l], &f[i][i + l], &r[i][i + l], 0, 2, a[i + l - 1] + a[i + l]);
checkAndUpdate(-f[i][i + l - 1] + a[i + l], &f[i][i + l], &r[i][i + l], 0, 1, a[i + l]);
}
}
int lB = 0, rB = n - 1;
int pl = 1;
int score[2];
memset(score, 0, sizeof(score));
while (lB != rB) {
printf("PL%d take %d from the left side, %d from the right side, current score=%d\n", pl, r[lB][rB].lDelta, r[lB][rB].rDelta, score[pl-1]+=r[lB][rB].score);
int tmp = r[lB][rB].lDelta;
rB -= r[lB][rB].rDelta;
lB += tmp;
pl = 3 - pl;
}
printf("PL%d takes the remaing coins, score=%d\n", pl, score[pl-1]+=r[lB][rB].score);
printf("Final score:\tPL1=%d, Pl2=%d\t\n", score[0], score[1]);
}
运行结果:
Input:
5
-11 5 3 6 -1
Output:
PL1 take 0 from the left side, 1 from the right side, current score=-1
PL2 take 0 from the left side, 2 from the right side, current score=9
PL1 take 0 from the left side, 1 from the right side, current score=4
PL2 takes the remaing coins, score=-2
Final score: PL1=4, Pl2=-2
Input:
8
-34 -1 94 111 43 78 -79 13
Output:
PL1 take 0 from the left side, 1 from the right side, current score=13
PL2 take 0 from the left side, 2 from the right side, current score=-1
PL1 take 0 from the left side, 2 from the right side, current score=167
PL2 take 0 from the left side, 2 from the right side, current score=92
PL1 takes the remaing coins, score=133
Final score: PL1=133, Pl2=92