添加到@彼得動態規劃的解決方案:
我覺得復發看起來有點像以下:
考慮硬幣堆從A[i,..j]
令,dp[i, j]
代表了最高分數PLAYER1都不可能得到。然後,
dp[i, j] = MAX {
MIN(dp[i+2, j], dp[i+1, j-1], dp[i+2, j-1]) + A[i], //Case when Player2 will try to make the most of it if Player1 picks ith coin.
MIN(dp[i+1, j-1], dp[i, j-2], dp[i+1, j-2]) + A[j], //Case when Player2 will try to make the most of it if Player1 picks the jth coin.
MIN(dp[i+2, j-1], dp[i+1, j-2], dp[i+2, j-2]) + A[i] + A[j] // Case when Player2 will try to make the most of it when Player1 picks both the ith and jth coins.
}
由於只有N^2個可能的遊戲狀態。它可以通過填充大小爲N^2的dp表來實現。
對於C++球迷:
#include<iostream>
using namespace std;
int Solve(int A[], int N, int **dp, int i, int j){
if(dp[i][j] != -1)
return dp[i][j];
if(j<i)
return 0;
else if(j==i)
return A[i];
else if((j-i) == 1)
return (A[i] + A[j]);
else{
int opt1 = min(Solve(A, N, dp, i+2, j), Solve(A, N, dp, i+1, j-1));
opt1 = min(opt1, Solve(A, N, dp, i+2, j-1));
int opt2 = min(Solve(A, N, dp, i+1, j-1), Solve(A, N, dp, i, j-2));
opt2 = min(opt2, Solve(A, N, dp, i+1, j-2));
int opt3 = min(Solve(A, N, dp, i+2, j-1), Solve(A, N, dp, i+1, j-2));
opt3 = min(opt3, Solve(A, N, dp, i+2, j-2));
int res = max(opt1+A[i], opt2+A[j]);
res = max(res, opt3+A[i]+A[j]);
dp[i][j] = res;
return res;
}
}
int main(){
int N;
int A[N];
cin >> N;
for(int i=0; i<N; ++i)
cin >> A[i];
int **dp;
dp = new int* [N];
for(int i=0; i<N; ++i)
dp[i] = new int[N];
for(int i=0; i<N; ++i)
for(int j=0; j<N; ++j)
dp[i][j] = -1;
Solve(A, N, dp, 0, N-1);
cout << dp[0][N-1] << endl;
for(int i=0; i<N; ++i)
delete [] dp[i];
delete []dp;
return 0;
}
此外,作爲@Peter指出你的分析第二個例子是錯誤的。玩家1實際上有一個通過得分102硬幣贏得比賽的策略。
這聽起來像一個家庭作業。你迄今爲止嘗試過哪些方法不適合你? –
兩個快速註釋 - 一個有用,另一個不是。 (1)您是否熟悉** [minimax算法](http://en.wikipedia.org/wiki/Minimax)**?雖然問題可能會更容易解決 - 它仍然是一個強大的工具。 (2)我相信如果你想得到一個「抽獎」 - 我的直覺告訴我這將相當於分區問題,這是NP-Complete(對你沒有用處,但至少對我有用)。 – amit
@KenWhite - 雖然這是一個有趣的問題,我很高興這不是我的作業 - 太難了:)除了我自己學習算法。 好吧,我將閱讀有關極小極大算法。 – xan