uva 10891 - Game of Sum

Problem E
Game of Sum
Input File: 
e.in

Output: Standard Output

 

This is a two player game. Initially there are n integer numbers in an array and players A and B get chance to take them alternatively. Each player can take one or more numbers from the left or right end of the array but cannot take from both ends at a time. He can take as many consecutive numbers as he wants during his time. The game ends when all numbers are taken from the array by the players. The point of each player is calculated by the summation of the numbers, which he has taken. Each player tries to achieve more points from other. If both players play optimally and player A starts the game then how much more point can player A get than player B?

Input

The input consists of a number of cases. Each case starts with a line specifying the integer n (0 < n ≤100), the number of elements in the array. After that, n numbers are given for the game. Input is terminated by a line where n=0.

 

Output

For each test case, print a number, which represents the maximum difference that the first player obtained after playing this game optimally.

 

Sample Input                                Output for Sample Input

4

4 -10 -20 7

4

1 2 3 4

0

7

10

简单的区间dp,dp[i][j]表示区间[i,j]先取数者分数-后取数者分数的最大值。

初始化区间长度1和2的,从区间长度为3开始递推,

dp[i][j]={sum[i...k]-dp[k+1][j],dp[i][k-1]+sum[k...j]},显然k=i或j时,k+1>j或者k-1<i,此时单独计算,其余i+1<=k<=j-1正常递推,没有任何难度,水题一道。

代码:

#include<cstdio>
#include<iostream>
using namespace std;

int dp[110][110];
int a[110],sum[110];
int main()
{
    int n;
    while(scanf("%d",&n),n){
        for(int i=1;i<=n;i++){
            scanf("%d",a+i);
            sum[i]=sum[i-1]+a[i];
        }
        for(int i=1;i<n;i++){
            dp[i][i]=a[i];
            dp[i][i+1]=max(a[i]+a[i+1],a[i]-a[i+1]);
            dp[i][i+1]=max(dp[i][i+1],a[i+1]-a[i]);
        }
        dp[n][n]=a[n];
        for(int l=2;l<n;l++)
            for(int i=1,j=l+1;j<=n;i++,j++){
                dp[i][j]=max(a[i]-dp[i+1][j],a[j]-dp[i][j-1]);
                dp[i][j]=max(dp[i][j],sum[j]-sum[i-1]);
                for(int k=i+1;k<=j-1;k++){
                    int t=max(sum[k]-sum[i-1]-dp[k+1][j],sum[j]-sum[k-1]-dp[i][k-1]);
                    dp[i][j]=max(dp[i][j],t);
                }
            }
        printf("%d\n",dp[1][n]);
    }
	return 0;
}


无意间在网上又搜到一种解法,虽然我感觉没我的方法来的快捷,但是总归还算是一种不错的思路,在这里补上:

这是一道经典动态规划试题的变形,也是拓展。我们先看看它经典原型。

   题目:两个玩家A和B在玩一个取石子游戏,且每个石子都有它们各自的价值。在游戏中有这样一个规则:每次取一个石子必行从两端取,要么是最左端,要么是最右端,直到取完为止。两个玩家都非常聪明,他们每次都会去最优的结果。给他们N个石子,你能计算出玩家A,B各自的最后结果吗?假设总是玩家A先开局。

   对于这题,我们考虑best[i][j]表示开局者玩家Aij部分得到最大和,sum[i][j]表示从ij和,由于只能从两端取石子,要么有从最左端,要么从最右端。则有转移方程:

    best[i][j]=sum[i][j]-min(best[i][j-1],best[i+1][j]); 目标状态:best[1][n]

那么推广到这题,可以取连续的,我们同样稍改变下即可。

    best[i][j]=sum[i][j]-min(best[i][j-k],best[i+k][j]);{1<=k=j-i+1}.

   目标状态: best[1][n]-(sum[1][n]-best[1][n])

还有显然两者的初始化: best[i][i]=a[i];


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值