题目链接:https://nanti.jisuanke.com/t/48
题目描述
有如下一个双人游戏:N个正整数的序列放在一个游戏平台上,两人轮流从序列的两端取数,每次有数字被一个玩家取走后,这个数字被从序列中去掉并累加到取走该数的玩家的得分中,当数取尽时,游戏结束。以最终得分多者为胜。
编一个执行最优策略的程序,最优策略就是使自己能得到在当前情况下最大的可能的总分的策略。你的程序要始终为两位玩家执行最优策略。
输入第1行包括一个正整数N(2≤N≤100), 表示序列中正整数的个数。输入第2行包含用空格分隔的N个正整数(1≤所有正整数≤200)。
只有一行,用空格分隔的两个整数: 依次为先取数玩家和后取数玩家的最终得分。
样例输入复制
6 4 7 2 9 5 2
样例输出复制
18 11
sum[i][j]表示从i位到j位所有的和,dp[i][j]表示从i位到j位使自身取到的所有值的最大和
想一下,先手要取掉两端中的一个值,此时无论先取者还是后取者都希望自己取的是最优的。
何为最优?
都保证自己会取得保证取完后总和相对大的,如何表示?
对于先手而言,
先取左边还是右边?当先手取完,就轮到后手去,后手一定会选择当前能令他得到最大分数的策略,其实当先手在[x, y]区间两端取走一个数,那么后手面临两个状态[x+1, y]和[x, y-1],先手想要取得最大值,一定会想让后手取这两种状态中的较小值,
即:dp[i][j]=sum[i][j]-min(dp[i+1][j],dp[i][j-1]),后半部分为后者所得和,前者所得和为总和减后者的和。。。。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int a[105],sum[105][105],dp[105][105];
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
dp[i][i]=a[i];
sum[i][i]=a[i];
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
sum[i][j]=sum[i][j-1]+a[j];
}
}
for(int i=n-1;i>=0;i--){
for(int j=i;j<n;j++){
dp[i][j]=sum[i][j]-min(dp[i+1][j],dp[i][j-1]);
}
}
printf("%d %d\n",dp[0][n-1],sum[0][n-1]-dp[0][n-1]);
}