在主城站街很久之后,小萌决定不能就这样的浪费时间虚度青春,他打算去打副本。
这次的副本只有一个BOSS,而且BOSS是不需要击杀的,只需要和它比智力…….
BOSS会列出一正整数的序列,由小萌先开始,然后两个人轮流从序列的任意一端取数,取得的数累加到积分里,当所有数都取完,游戏结束。
假设小萌和BOSS都很聪明,两个人取数的方法都是最优策略,问最后两人得分各是多少。
输入
整数个数N
用空格隔开的N个正整数(1 ≤ a[i] ≤ 1000)
输出
只有一行,用空格隔开的两个数,小萌的得分和BOSS的得分。
样例输入:
6 4 7 2 9 5 2
样例输出:
18 11
定义一个数组a[n]接受输入
定义一个矩阵L,L[i][j]代表某人先取,从数组a中下标i到j的数中最大能取的值
如果只有一个数,这个人只能取这个数
即L[i][j]=a[i]
0 | 1 | 2 | 3 | 4 | 5 | |
0 | 4 | |||||
1 | 7 | |||||
2 | 2 | |||||
3 | 9 | |||||
4 | 5 | |||||
5 | 2 |
如果有两个数,这个人先取,他会取最大的数
两个数的总和是一定的,也可以看出他取了某个数之后要使得另一个人取的数最小,他才能取得最大
对于从i到j的数来说,这些数的和是一定的,某人只能取两端的数,他要使得自己取得的数总和最大,他就要在取了这个数之后,使得另一个人在剩下的数中取得的最大值最小,而另外一个人的取法是在第一个人取了第i或第j个数后,他会在i+1到j或i到j-1中取最大值,即L[i+1][j]或L[i][j-1]
这样,第一个人取的想法就应该是使得另一个人取的L[i+1][j]和L[i][j-1]中较小的一个值,而他,也就是L[i][j]=max(sum(i,j)-L[i+1][j],sum(i,j)-L[i][j-1])
递推式:
#include<iostream>
using namespace std;
int L[10][10]={0};
void f(int n,int*a);
void sum(int*a,int i,int j);
int main()
{
int n;
cin>>n;
int a[10];
for(int i=0;i<n;i++)
cin>>a[i];
f(n,a);
return 0;
}
int s(int *a,int i,int j)
{
int sum=0;
for(int k=i;k<=j;k++)
sum+=a[k];
return sum;
}
void f(int n,int*a)
{
for(int flag=0;flag<=n;flag++)//这里可以看成沿着矩阵对角线进行每一轮的循环,flag代表循环的次数
//当循环n次时,可以得到L[0][n-1];
{
for(int i=0;i<n-flag;i++)//每一次循环从矩阵的第0行开始
{
int j=i+flag;//第flag+1次循环时,坐标为(i,i+flag)
if(i==j)
L[i][j]=a[i];
else
{
L[i][j]=max(s(a,i,j)-L[i][j-1],s(a,i,j)-L[i+1][j]);//递推式
}
}
}
cout<<L[0][n-1]<<' '<<s(a,0,n-1)-L[0][n-1];
}