标签:int pac i+1 组成 lightoj scanf min class return
在此游戏中任意时刻的状态都是原始序列的一段子序列故:
定义d(i, j) : 表示原来序列的第i ~ j个元素组成的子序列,在双方都采取最优策略的情况下,先手得分的最大值、
状态转移时,需要枚举从左边或者从右边取多少个。因此
d(i, j) = sum[i, j] - min{d(i+1, j), d(i + 2, j).....d(j, j) , d(i, j-1), d(i, j-2),, ... , d(i, i), 0}
其中sum[i, j] 是元素i 到j 的和。这里的0是取完所有的数, 有了它方程就不需要显式的边界条件了。
答案是 d(1, n) - (sum[1, n] - d(1, n)) = 2*d(1, n) - sum[1, n]
先手 后手
记忆话一下就可以了
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 5 using namespace std; 6 #define MAXN 110 7 #define inf 100000000 8 9 int dp[MAXN][MAXN]; 10 int z[MAXN]; 11 int sum[MAXN]; 12 bool vis[MAXN][MAXN]; 13 14 15 int d(int a,int b) 16 { 17 if(vis[a][b]) 18 return dp[a][b]; 19 vis[a][b]=1; 20 int m=0; 21 int i; 22 for(i=a+1;i<=b;i++)m=min(m,d(i,b)); 23 for(i=a;i<=b;i++)m=min(m,d(a,i)); 24 dp[a][b]=sum[b]-sum[a-1]-m; 25 return dp[a][b]; 26 } 27 int main() 28 { 29 int t,ca; 30 scanf("%d",&t); 31 ca=1; 32 33 while(t--) 34 { 35 int n,i; 36 scanf("%d",&n); 37 memset(vis,0,sizeof(vis)); 38 memset(dp,0,sizeof(dp)); 39 for(i=1;i<=n;i++) 40 { 41 scanf("%d",&z[i]); 42 sum[i]=sum[i-1]+z[i]; 43 } 44 45 printf("Case %d: %d\n",ca++,2*d(1,n)-sum[n]); 46 } 47 return 0; 48 }
标签:int pac i+1 组成 lightoj scanf min class return
原文地址:http://www.cnblogs.com/cherryMJY/p/6075770.html