标签:
题目大意:首先输入n(n ≤ 1000),n为偶数,接着输入n个整数,n个整数的和不超过1,000,000.两个人每次只能从两端取数,第一个人A可以用任意策略,第二个人B用贪心策略(左右数相等取左数)。求在保证第一个人取得的和最大的前提下,两人取数和之差的最大值。
解题思路:动态规划。突破口在于A能取两头的数,B只能取两头最大数(相同取左),而每次取完一个数,能取数的区间就会减少一个。对A来说,每次取数有两种选择,如果A知道在更少区间范围的最优和之差,则可以作出最优的选择。对B来说,每次只能用贪心选数,比较容易。
a[i] 表示第i位的数。(0 ≤ i < n)
m[i][j] 表示剩余为 i -> j 时的最优和之差。(0 ≤ i ≤ j < n)
当区间为奇数时(即(j-i+1) % 2 == 1),B选择数,用贪心的策略:
若 a[i] >= a[j] , 则 m[i][j] = m[i+1][j] - a[i].
若 a[i] < a[j] , 则 m[i][j] = m[i][j-1] - a[j].
当区间为偶数时(即(j-i+1) % 2 == 0),A选择数,枚举两端取数,选择最优和之差:
m[i][j] = max(a[i] + m[i+1][j], a[j] + m[i][j-1]).
代码如下:
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 const int maxn = 1005; 6 int m[maxn][maxn]; // m[i][j] 代表 剩余 i -> j 区间时的第一人最大获利 7 // 若 区间为奇数 j - i + 1 是奇数,则让第二人根据贪心算法先选择 8 // 若 区间为偶数 j - i + 1 是偶数,则让第一人根据最大利益先选择 9 int a[maxn]; 10 int n; 11 12 void init(int n) { 13 for (int i = 0; i < n; i++) { 14 for (int j = 0; j < n; j++) { 15 m[i][j] = 0; 16 } 17 } 18 } 19 20 int main() { 21 int t = 0; 22 while (cin >> n, n != 0) { 23 t++; 24 for (int i = 0; i < n; i++) { 25 cin >> a[i]; 26 } 27 28 init(n); // 初始化矩阵 29 30 for (int i = 1; i <= n; i++) { 31 for (int j = 0; j < n; j++) { 32 int k = j + i - 1; 33 if (k > n - 1) break; 34 // j -> k 为区间左右端点 35 if (i % 2 == 1) { // 奇数区间,第二人先选择 36 if (a[j] >= a[k]) { // 左边端点较大或相等 37 m[j][k] = m[j + 1][k] - a[j]; 38 } else { // 左边端点较小 39 m[j][k] = m[j][k - 1] - a[k]; 40 } 41 } else { // 偶数区间,第一人先选择 42 m[j][k] = max(a[j]+m[j+1][k], a[k]+m[j][k-1]); 43 } 44 } 45 } 46 47 cout << "In game " << t << ", the greedy strategy might lose by as many as " << m[0][n-1] << " points." << endl; 48 } 49 50 return 0; 51 }
标签:
原文地址:http://www.cnblogs.com/mchcylh/p/4837342.html