UVa 10891 Game of Sum(经典博弈区间DP)

题意:

给定n个数字,A和B可以从这串数字的两端任意选数字,一次只能从一端选取。

并且A B都尽力使自己选择的结果为最大的,可以理解成A B每一步走的都是最优的。

如果A先选择,则A B差值最大是多少。

思路:

http://hi.baidu.com/knowledgetime/item/d8ec9420a2b2f98daf48f5a4

第一次做类似的博弈题目,不过还是不难理解的。上面题解还是有一点说的不到位的。

dp[i, j]表示区间[i, j]范围内能选择的最大数。这个最大数不管是A还是B,也就是说可以当作是A B交替的。

由于区间范围是不断扩张的,所以求大区间的最大值时就要向小区间询问,此时小区间相当于是个Oracle,无所不知,只管负责问就行了。

于是对于此题A B可以从两端选取任意多值,所以当A求dp[i, j]时需要询问的区间(而且还要从两端分别)为[i, k],[k+1, j](i <= k < j)

询问的这些子区间可以当作是B所能达到的最大值,使这些B最优值达到最小,即是A的目的。

最后还要考虑一点就是:如果A把区间[i, j]全部取完,还要和上述得到的结果作个比较。

#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #include <algorithm>

using namespace std; const int MAXN = 110; int dp[MAXN][MAXN]; int a[MAXN], sum[MAXN]; int main() { int n; while (scanf("%d", &n) && n) { sum[0] = 0; for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), sum[i] = a[i] + sum[i-1]; for (int i = 1; i <= n; ++i) dp[i][i] = a[i]; for (int p = 2; p <= n; ++p) { for (int i = 1, j = p; j <= n; ++i, ++j) { int ans = INT_MIN; for (int k = i; k < j; ++k) { int m = min(dp[i][k], dp[k+1][j]); m = sum[j] - sum[i-1] - m; if (ans < m) ans = m; } if (ans < sum[j] - sum[i-1]) ans = sum[j] - sum[i-1]; dp[i][j] = ans; } } printf("%d\n", 2 * dp[1][n] - (sum[n] - sum[0])); } return 0; }

 

你可能感兴趣的:(game)