问题在于遵循以下规则在游戏的每个时刻选择最佳选项:
您只能选择最左边或最右边的卡片。
您的对手将始终先选择,并始终从最左侧或最右侧的牌中选择最高牌。如果它是一个平局,它会选择最右边的。考虑到这并不总是最好的选择。
有时赢得胜利是不可能的,但无论如何你必须通过对抗这个对手(或策略,让我们说)来显示你可以添加的最高分。
示例:
Cards: 1 2 4 2 8 4 3
Opponent: 3 4 2 2 = 11
Me: 1 8 4 = 13
在这里,我在第二回合选择了1而不是4,所以我可以选择8。这就是为什么选择最高卡并不总是最好的。
我一直在尝试使用递归来实现此解决方案,但我不确定它是最好的选择。关于如何设计这种算法的任何想法?
[编辑] 感谢@PengOne的慷慨帮助。这是我试图实现的代码,但不幸的是它给了我错误。我该怎么办呢?随着我的进步,我正在编辑这个。
static int cardGameValue(List<int> D, int myScore, int opponentScore)
{
if (D.Count == 0) return myScore;
else
{
if (D[0] <= D[D.Count - 1])
{
opponentScore += D[D.Count - 1];
D.RemoveAt(D.Count - 1);
}
else
{
opponentScore += D[0];
D.RemoveAt(0);
}
int left = cardGameValue(
new List<int>(D.GetRange(1, D.Count - 1)),
myScore + D[0],
opponentScore);
int right = cardGameValue(
new List<int>(D.Take(D.Count - 2)),
myScore + D[D.Count - 1],
opponentScore);
if (left >= right)
{ return left; }
else
{ return right; }
}
}
答案 0 :(得分:4)
使用递归从最简单的情况构建解决方案。
让D
成为卡片阵列。让A
成为你牌的总数,B
是对手牌的总数。将S = A-B
设置为游戏的值。如果S>0
,则会获胜,如果S<0
则会失败,如果S==0
则会失败。
最简单的是一次做两个动作,你的动作接着是对手的决心。有两个基本案例需要考虑:
如果length(D) == 0
,请返回S
。游戏结束了。
如果length(D) == 1
,请返回S + D[0]
。您选择剩余的卡片,游戏结束。
对于递归情况,当length(D) > 1
时,评估两种可能性
如果您选择左侧牌,然后是对手进行确定性移动,则让L
成为游戏的结果,即
L = D[0] - max(D[1],D[N-1]) + cardGameValue(newD)
如果你选择了正确的牌,然后是对手做出他的确定性移动,那么让R
成为游戏的结果,即
R = D[N-1] - max(D[0],D[N-2]) + cardGameValue(newD)
选择与较大数字相对应的游戏,即D[0]
L>=R
,然后选择D[N-1]
。这里N = length(D)
。
答案 1 :(得分:3)
您应该查看Min-Max Algorithm,可能会查看Alpha-Beta pruning
Min-Max认为你的对手总是会为自己选择最佳选择,因此你可以运行每个可能的场景来发现最能让你击败对手的选择。 “即,如果我移动x,我的对手将采取行动y,然后我将采取......”等,一直到游戏结束。因此,您可以确定谁将获胜。
Alpha-Beta修剪类似于它查看可能的场景,但它确定可能的场景列表是否会产生获胜结果。如果你知道如果你做“移动x”那么无论如何你总是会松动,你不需要花更多的时间看“移动x然后移动y”。你可以从“移动x”中“修剪”整个选择分支,因为你知道它永远不会有帮助。
答案 2 :(得分:2)
这是最终实际工作的代码。感谢大家的支持。
static int cardGameValue(List<int> D, int myScore, int opponentScore)
{
if (D.Count == 0) return myScore;
else if (D.Count == 1)
{
opponentScore += D[0];
return myScore;
}
else
{
if (D[0] <= D[D.Count - 1])
{
opponentScore += D[D.Count - 1];
D.RemoveAt(D.Count - 1);
}
else
{
opponentScore += D[0];
D.RemoveAt(0);
}
int left = cardGameValue(new List<int>(D.GetRange(1, D.Count - 1)), myScore + D[0], opponentScore);
int right = cardGameValue(new List<int>(D.GetRange(0, D.Count - 1)), myScore + D[D.Count - 1], opponentScore);
if (left >= right)
{
return left;
}
else
{
return right;
}
}
}