题意:经典的取石子游戏是这样的:有一堆石子,A、B两个人轮流取,每次取一颗,只能从边上取,每个石子有相应的价值,A、B两人都想使得自己的价值最多,两个人足够聪明,问最后价值分别是多少
本题则是可以取多颗,但仍然只能从一侧取得
分析:状态转移方程
best[i][j]=sum[i][j]-min(best[i][j-k],best[i+k][j], 0);{1<=k=j-i+1}.
使用了记忆化的方法,O(n3),书上说有进一步的优化,不过当前数据下已经很快了(64ms)
代码:
View Code
1 #include <stdio.h> 2 #include <iostream> 3 #include <string.h> 4 using namespace std; 5 const int MAXN = 100 + 10; 6 #define DEBUG 7 int min(int a, int b){ 8 return a<b?a:b; 9 } 10 int s[MAXN], a[MAXN], d[MAXN][MAXN], vis[MAXN][MAXN], n; 11 int dp(int i, int j){ 12 if(vis[i][j]) return d[i][j]; 13 vis[i][j]=1; 14 int m=0, k; 15 for(k=i+1; k<=j; k++) m=min(m, dp(k, j)); 16 for(k=i; k<j; k++) m=min(m, dp(i, k)); 17 d[i][j]=s[j]-s[i-1]-m;; 18 return d[i][j]; 19 } 20 int main(){ 21 #ifndef DEBUG 22 freopen("in.txt", "r", stdin); 23 #endif 24 while(scanf("%d", &n)!=EOF && n){ 25 s[0]=0; 26 int i; 27 for(i=1; i<=n; i++){ 28 scanf("%d", &a[i]); 29 s[i] = s[i-1] + a[i]; 30 } 31 memset(vis, 0, sizeof(vis)); 32 printf("%d\n", 2*dp(1,n)-s[n]); 33 } 34 return 0; 35 }