标签:
问题来源:刘汝佳《算法竞赛入门经典--训练指南》 P67 例题28:
问题描述:有一个长度为n的整数序列,两个游戏者A和B轮流取数,A先取,每次可以从左端或者右端取一个或多个数,但不能两端都取,所有数都被取完时游戏结束,然后统计每个人取走的所有数字之和作为得分,两人的策略都是使自己的得分尽可能高,并且都足够聪明,求A的得分减去B的得分的结果。
问题分析:1.设dp[i][j]表示从第i到第j的数的序列中,双方都采取最优策略的前提下,先手得分的最大值
2.若求dp[i][j],我们可以枚举从左边(或者右边)取多少个数,并求枚举过程中dp[i][j]的最大值,则有状态转移方程:
dp[i][j] = sum[i][j] - Min{dp[i+1][j],dp[i+2][j],...,dp[j][j], dp[i][i],dp[i][i+1],...,dp[i][j-1]}
(其中sum[i][j] 表示从i到j的序列和)
例题链接:...
例题:UVa 10891
;
代码:
1 #include "stdio.h" 2 #include "string.h" 3 #define N 105 4 int a[N]; 5 int sum[N]; 6 int dp[N][N],mark[N][N]; 7 8 int inline Min(int a,int b) { return a<b?a:b; } 9 10 int DP(int i,int j) //记忆化搜索 11 { 12 if(mark[i][j]) 13 return dp[i][j]; 14 mark[i][j] = 1; 15 int m = 0; //全部取光 16 for(int k=i+1; k<=j; k++) 17 m = Min(m,DP(k,j)); 18 for(int k=j-1; k>=i; k--) 19 m = Min(m,DP(i,k)); 20 dp[i][j] = sum[j] - sum[i-1] - m; 21 return dp[i][j]; 22 } 23 24 int main() 25 { 26 int n; 27 int i,j,k; 28 while(scanf("%d",&n) == 1) 29 { 30 for(i=1; i<=n; i++) 31 scanf("%d",&a[i]); 32 memset(sum,0,sizeof(sum)); 33 for(i=1; i<=n; i++) 34 sum[i] = sum[i-1] + a[i]; 35 memset(dp,0,sizeof(dp)); 36 memset(mark,0,sizeof(mark)); //标记初始化 37 printf("%d\n",2*DP(1,n)-s[n]); 38 } 39 return 0; 40 }
09_Sum游戏(UVa 10891 Game of Sum)
标签:
原文地址:http://www.cnblogs.com/ruo-yu/p/4388130.html