Coins in a Line
1. 题目:给定一组硬币排成直线(假设硬币数量为偶数),有两个人开始取硬币。每次只能从队列两端取硬币。有没有这样一种方案使先手取硬币,最后得到的硬币面值最大?给出这样一种方案并给出取法及最终获得的最大面值。
2. 文章中给出了详细的解释,这类就不说了。
3. 代码:
1 #include <iostream> 2 #include <cassert> 3 4 using namespace std; 5 const int MAX_N = 100; 6 7 void printMoves(int P[][MAX_N], int A[], int N) { 8 int sum1 = 0, sum2 = 0; 9 int m = 0, n = N-1; 10 bool myTurn = true; 11 while (m <= n) { 12 int P1 = P[m+1][n]; // If take A[m], opponent can get... 13 int P2 = P[m][n-1]; // If take A[n] 14 cout << (myTurn ? "I" : "You") << " take coin no. "; 15 if (P1 <= P2) { 16 cout << m+1 << " (" << A[m] << ")"; 17 m++; 18 } else { 19 cout << n+1 << " (" << A[n] << ")"; 20 n--; 21 } 22 cout << (myTurn ? ", " : ".\n"); 23 myTurn = !myTurn; 24 } 25 cout << "\nThe total amount of money (maximum) I get is " << P[0][N-1] << ".\n"; 26 } 27 28 int maxMoney(int A[], int N) { 29 int P[MAX_N][MAX_N] = {0}; 30 int a, b, c; 31 for (int i = 0; i < N; i++) { 32 for (int m = 0, n = i; n < N; m++, n++) { 33 assert(m < N); assert(n < N); 34 a = ((m+2 <= N-1) ? P[m+2][n] : 0); 35 b = ((m+1 <= N-1 && n-1 >= 0) ? P[m+1][n-1] : 0); 36 c = ((n-2 >= 0) ? P[m][n-2] : 0); 37 P[m][n] = max(A[m] + min(a,b), 38 A[n] + min(b,c)); 39 } 40 } 41 printMoves(P, A, N); 42 return P[0][N-1]; 43 } 44 45 int main() 46 { 47 enum{length=8}; 48 //int a[length]={10,5,8,31,32,12,2,3}; 49 int a[length]={10,5,8,11,9,12,2,3}; 50 maxMoney(a,length); 51 return 0; 52 }
4. 最后给出的思考,如果可以要求对方按照自己的意愿选择,求出最终的最大面值。这个按照上面的思路,貌似不行,比如,递归式修改如下:
P(i, j) = max { P1, P2 }
= max { Ai + max{ P(i+2, j), P(i+1, j-1) },
Aj + max { P(i+1, j-1), P(i, j-2) } }
自己写程序试了下,发现结果不对。不过感觉递归式没错,不知道是为什么?
5. 又是一道dp的题目,自己最初还是没有思路。唉,路漫漫其修远兮!!!
6. 参考文章: