1176. Two Ends
题目链接地址:http://soj.me/1176
题目大意:两头取数。第一个人随机取,第二个人用贪婪算法(每次都取大的),求两人取数在第一个人赢的情况下的最大分差。使用贪婪算法时,如果左右两边相等,取左边的。
核心算法:动态规划。
设数组arr[a][b]是在数列区间[a,b]上的最大分差。
递推公式:
1.第一个人取左边的数arr[a]
if(arr[a+1] >= arr[b]) point1 = input[a] - input[a+1] + dp(a+2,b);
else point1 = input[a] - input[b] + dp(a+1, b-1);
2.第一个人取右边的数arr[b]
if (input[a] >= input[b-1]) point2 = input[b] - input[a] + dp(a+1,b-1);
else point2 = input[b] - input[b-1] + dp(a,b-2);
arr[a][b] = point1 > point2 ? point1 : point2;
代码:
1 // 动态规划! 2 #include <stdio.h> 3 4 #define N 1005 5 #define ENDLESS 100000 6 7 int arr[N][N]; 8 int input[N]; 9 10 int dp(int a, int b) { 11 if (arr[a][b] != ENDLESS) 12 return arr[a][b]; 13 14 if (a > b) 15 return 0; 16 17 // 第一个人取左边的数,第二个人贪婪算法 18 int point1; 19 if (input[a+1] >= input[b]) { 20 point1 = input[a] - input[a+1] + dp(a+2,b); 21 } else { 22 point1 = input[a] - input[b] + dp(a+1, b-1); 23 } 24 25 // 第一个人取右边的数,第二个人贪婪算法 26 int point2; 27 if (input[a] >= input[b-1]) { 28 point2 = input[b] - input[a] + dp(a+1,b-1); 29 } else { 30 point2 = input[b] - input[b-1] + dp(a,b-2); 31 } 32 33 arr[a][b] = point1 > point2 ? point1 : point2; 34 35 return arr[a][b]; 36 } 37 38 int main() { 39 int n; 40 int count = 0; 41 while (scanf("%d", &n) != EOF) { 42 if (n == 0) 43 break; 44 45 for (int i = 0; i < n; i++) 46 scanf("%d", &input[i]); 47 48 for (int i = 0; i < n; i++) 49 for (int j = 0; j < n; j++) 50 arr[i][j] = ENDLESS; 51 52 printf("In game %d, the greedy strategy might lose by as many as %d points.\n", ++count, dp(0,n-1)); 53 } 54 return 0; 55 }