codevs3196 黄金宝藏

题目描述 Description

小毛终于到达宝藏点,他意外地发现有一个外星人(名叫Pluto)。宝藏是一些太空黄金,有n堆排成一行,每堆中有xi颗黄金。小毛和Pluto决定轮流从中取出黄金,规则是每次只能从最左边或最右边取出一堆黄金,直到所有黄金被取出。小毛先取,两人都以最优策略进行选取,求两人的最后所得。

输入描述 Input Description

第一行是正数n(≤500);第二行为n个正整数xi(≤300),表示每堆黄金的个数。

输出描述 Output Description

仅两个整数,分别表示小毛和Pluto的得分,以空格隔开。

样例输入 Sample Input

4 7 2 9 5 2

样例输出 Sample Output

18 11

 
题解:
  设dp[i][j]表示当取到只剩下i~j的元素时的先手的最优得分,这个转移非常好像,但第一次写类似博弈的题目,写详细一些。
  首先我们有两种决策,对于区间i~j,可以取a[i],也可以取a[j],当我们取a[i]时,对手就还剩下区间i+1~j,那么此时他就变成了先手,按照最优策略取了dp[i+1][j],如果取a[j],那么还剩下区间i~j-1,那么他就会取dp[i][j-1],因为我们两个人的所取的总和是不变的,都是区间和,那么我们只有最小化他的取值,才能得到我们想要的最大得分。所以dp[i][i+len]=sum[i+len]-sum[i-1]-min(dp[i+1][i+len],dp[i][i+len-1]),因为我们是在保证后手也是用最优策略的情况下做出的判断,而转移也是用最优的转移,所以符合题意。
代码:
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<stdlib.h>
#include<algorithm>
#define MANX 1000
using namespace std;
int dp[MANX][MANX],a[MANX],sum[MANX];
int n;
int main(){
    scanf("%d",&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];
    for(int len=1;len<=n-1;len++)
    for(int i=1;i+len<=n;i++)
    dp[i][i+len]=sum[i+len]-sum[i-1]-min(dp[i+1][i+len],dp[i][i+len-1]);
    printf("%d %d
",dp[1][n],sum[n]-dp[1][n]);
}
原文地址:https://www.cnblogs.com/renjianshige/p/7453834.html