UVA 10891——Game of Sum

题目大意:

有n个数字排成一条直线,然后有两个小伙伴来玩游戏, 每个小伙伴每次可以从两端(左或右)中的任意一端取走一个或若干个数(获得价值为取走数之和), 但是他取走的方式一定要让他在游戏结束时价值尽量的高,最头疼的是两个小伙伴都很聪明,所以每一轮两人都将按照对自己最有利的方法去取数字,请你算一下在游戏结束时,先取数的人价值与后取数人价值之差(不要求绝对值)。


有一个比这道题简单一点的题,是两边只能一个一个地取,做法如下:

dp[i][j]表示i到j取到的最优值,用dp[i+1][j]或dp[i][j-1]来更新,前缀和优化一下。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <cmath>
 6 using namespace std;
 7 const int maxn=1e4+5;
 8 
 9 int n;
10 int a,sum[maxn],dp[maxn][maxn];
11 
12 int main(){
13     scanf("%d",&n);
14     for(int i=1;i<=n;i++){
15         scanf("%d",&a);
16         dp[i][i]=a;
17         sum[i]=sum[i-1]+a;
18     }
19     for(int i=1;i<=n;i++){
20         for(int j=1;j+i<=n;j++){
21             dp[j][j+i]=sum[i+j]-sum[j-1]-min(dp[j+1][j+i],dp[j][j+i-1]);
22         }
23     }
24     printf("%d",dp[1][n]);
25     
26     
27     
28     return 0;
29 } 
View Code

而这道题对取牌区间进行一个枚举就行了:

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 const int maxn=1e3+5;
 8 const int inf=0x3f3f3f3f;
 9 int n,x,dp[maxn][maxn],sum[maxn];
10 
11 int main(){
12     ios::sync_with_stdio(false);
13     while(1){
14         cin>>n;
15         if(!n)break;
16         for(int i=1;i<=n;++i)
17             cin>>x,sum[i]=sum[i-1]+x,dp[i][i]=x;
18         for(int len=1;len<n;++len){
19             for(int r,l=1;(r=l+len)<=n;++l){
20                 int tmp=0;
21                 for(int k=1;k<=len;++k){
22                     tmp=min(tmp,min(dp[l+k][r],dp[l][r-k]));
23                 }
24                 dp[l][r]=sum[r]-sum[l-1]-tmp;
25             }
26         }
27         cout<<dp[1][n]*2-sum[n]<<endl;
28     }
29     
30     
31     
32     
33     return 0;
34 }

 

posted @ 2017-11-01 19:32  _ATHENS  阅读(268)  评论(0编辑  收藏  举报