有一个2人游戏,你有一系列数字,例如:2 -6 12
。让我们说他们写在卡片上。
游戏需要时间轮流。每个回合玩家都有义务从序列的开头或结尾(不跳过)中获取完全一张牌。在最后一张牌被拿走后游戏结束。目的是以尽可能高的正分数完成游戏(分数是玩家所采取的牌上所有数字的总和)。我们也知道两位球员都采用最佳策略(最大化他们的收益)。我们必须说出他们最终会得到什么分数。
知道最佳策略是什么样的吗?
到目前为止我的研究:
1-3 cards is trivial
{a}, no choice take a;
{a,b} take max(a,b) reduces to problem {a}
{a,b,c} take max(a,c) reduces to problem {a,b}
4 cards : {a,b,c,d}
if (a + max(c, min(b,d)) > d + max(b, min(a,c)))
take a;
else
take d;
如果我决定采用a
,我的对手采取max(b,d)作为3张牌策略说,所以我要做的是从c
取得最大值(这是“安全的”在对手转身时),从b
,d
卡开始变小,因为对手会占据更大的牌。 d
的双重情况。但我不知道如何扩展(如果可能的话)n卡的情况。
任何线索?
答案 0 :(得分:1)
//globals
int[N] cards;
int[N][N] v; //initialized to 0
int[N][N] sum; // precomputed such that sum(i,j)=cards[i]+...+cards[j]
void updateValue(int i,int j){
int left=cards[i]+sum(i+1,j)-v(i+1,j);
int right=cards[j]+sum(i,j-1)-v(i,j-1);
v[i,j]=max(left,right);
}
void do(){
for (int d=1;d<N;d++)
for (int i=0;i<N-d;i++)
updateValue(i,i+d);
}
答案将在值[0,N-1]
中通过注意以下内容可以改善内存使用:如果我们将v视为一个大的方形表,我们填充其上三角形的一半。对于外循环中的每个d值,我们填充从<0,d]到[N-d,N-1]的对角。现在请注意,在填充此对角线时,我们只使用之前对角线的值,因此我们并不需要将所有先前的值保存在内存中。
答案 1 :(得分:0)
您需要从基本案例开始并定义基本功能:
e.g. f1(a) -> a
f2(x, y ) -> max(x,y)
f3(x, y, z) -> max(f(x,y),z)
然后你需要定义更复杂的案例,如下所示:
if (a + max(c, min(b,d)) > d + max(b, min(a,c)))
take a;
else
take d;
这看起来像一个4输入函数,您可以使用之前定义的max和min。 像这样:
f2 (a, b,c, d) -> if (a + max(c, min(b,d)) > d + max(b, min(a,c))) then true, else false
f3(a, b,c, d) -> if(f2(a,b,c,d) then a else d
如果需要,您需要定义“基本”函数f2,f3和其他函数,然后将输入值替换为其他函数的输出。
我知道这不是一个解决方案,但希望是一个足够好的提示,以递归的方式开始推理。
答案 2 :(得分:0)
我觉得这样的事情会奏效:
int[] cards;
int low = 0;
int high = cards.length - 1;
int bestScore(int low, int high)
{
if (low > high)
return 0;
// our best score is our immediate score minus the opponents best response
int lowScore = cards[low] - bestScore(low + 1, high);
int highScore = cards[high] - bestScore(low, high - 1);
if (lowScore >= highScore)
return lowScore;
else
return highScore;
}
int bestMove(int low, int high)
{
int lowScore = cards[low] - bestScore(low + 1, high);
int highScore = cards[high] - bestScore(low, high - 1);
if (lowScore >= highScore)
return low;
else
return high;
}
答案 3 :(得分:0)
如果序列的长度是偶数,则回答:
第一个玩家总是有一个不松动的策略。关键的观察是,如果他愿意,第一个玩家可以收集偶数地方的所有数字,如果他愿意,他可以收集奇数地方的所有数字。所以他只需要事先检查哪个总和更大:
如果序列是{x_1,x_2,...,x_n},其中n = 2k
计算:A = x_1 + x_3 _... x_2k-1和B = x_2 + x_4 + ... + x_2k
如果A&gt; = B,首先选择x_2k,无论对手做什么,第一个玩家总是可以为某些i选择x_2i。如果A&lt; B,从选择x_1开始,无论对手做什么,第一个玩家总能为某些人选择x_2i + 1.