USACO/game1

A Game游戏

IOI'96 - Day 1

 

有如下一个双人游戏:N(2 <= N <= 100)个正整数的序列放在一个游戏平台上,游戏由玩家1开始,两人轮流从序列的两端取数,取数后该数字被去掉并累加到本玩家的得分中,当数取尽时,游戏结束。以最终得分多者为胜

描述

编一个执行最优策略的程序,最优策略就是使玩家在与最好的对手对弈时,能得到的在当前情况下最大的可能的总分的策略。你的程序要始终为第二位玩家执行最优策略。

格式

PROGRAM NAME: game1

INPUT FORMAT:

(file game1.in)

第一行: 正整数N, 表示序列中正整数的个数。

第二行至末尾: 用空格分隔的N个正整数(大小为1-200)。

OUTPUT FORMAT:

(file game1.out)

只有一行,用空格分隔的两个整数: 依次为玩家一和玩家二最终的得分。

SAMPLE INPUT

6 
4 7 2 9 5 2

SAMPLE OUTPUT

18 11

/**区间DP,经典**/
/********************************************************************************************
    最大的难关就是要想出如何表示状态,正确划分状态区间,然后状态转移方程就能很容易想出。
我们用dp[i][j]代表在本题的规则下,从数列{a[i]……a[j]}中先手能够取得的最大值。
状态转移方程dp[i][j]=sum{a[i]……a[j]}-min(dp[i+1][j],dp[i][j-1]).
     解释:假设本轮A先手,取的数列是{a[i]……a[j]},他只有两种选择:a[i]和a[j],那下一轮
他的对手就会成为先手,取得数列也是两种选择。而对应的状态是dp[i+1][j]和 dp[i][j-1].对于本
轮的先手A来说,他想要获胜必须保证他的对手B每次取的都是B所能取得的最小值,即他的对手取的
应该是dp[i+1][j]和dp[i][j-1]的最小值。
    细节:我们注意到了dp[i][j]与dp[i+1][j]和dp[i][j-1]有关,因此,当求dp[i][j]时,必须使
dp[i+1][j]和dp[i][j-1]都存在,因此i循环应该从n减到1,j应该从1加到n.
********************************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX 220
using namespace std;

int min(int a,int b)
{
    return a<b?a:b;
}
int main()
{

    freopen("game1.in","r",stdin);
    freopen("game1.out","w",stdout);
    int dp[MAX][MAX]= {0};
    int sum[MAX]= {0};
    int a[MAX]= {0};
    int j,k,i,n;

    scanf("%d",&n);

    for(i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
        dp[i][i]=a[i];
    }

    for(j=n-1; j>=1; j--)
        for(k=j+1; k<=n; k++)
            dp[j][k]=(sum[k]-sum[j-1])-min(dp[j+1][k],dp[j][k-1]);
    cout<<dp[1][n]<<" "<<sum[n]-dp[1][n]<<endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值