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 }
而这道题对取牌区间进行一个枚举就行了:
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 }