取数问题(区间dp入门)

取数问题(区间dp入门)

QWQ

题目描述
有一排N个数,你和小明2个人玩游戏,每个人轮流从2端取数,每次可以从左或右取,不能从中间取。你取的所有的数的和是你的得分,小明取的所有的数的和是小明的得分。如果你先取,你最多比小明多得多少分?
输入
第一行:一个整数n,范围在[0, 100]。
第二行:n个整数,每个数范围在[1, 10000]
输出
小明足够聪明时,你最多多得的分数。

样例输入

4
3 2 9 1 

样例输出

9

【样例解释】:
第1轮取3;
第2轮取2;
第1轮取9;
第3轮取1;
(3+9)-(2+1) = 9
老规矩,分析一下题目。
我们每次只能从左边取数或右边取数,不能从中间取数。
有些人就想说了,那我直接用贪心求哪个数大不就好了?这题也太水了吧。
有这思想的小盆友是错的,如果你不信我来举个栗子(QWQ)

4
1    2     100   10
a[1] a[2]  a[3]  a[4]

来吧,分析一下。
贪心思维:
第一轮我选a[4](因为a[4]>a[1])
小明选a[3](因为a[3]>a[2])
第一轮我选a[2](因为a[2]>a[1])
小明选a[1]
小明:a[1]+a[3]=101
我:a[4]+a[2]=12
这一看就是我亏了啊!!!
所以贪心思维是不可行的,我们应该换一种。
区间DP思维:
假如我选了a[1],那么小明就只能选a[2]或a[4]。
同理,
我们先开一个二维数组 f f f,用j模拟起点,i模拟长度。
定义 f [ j ] [ i + j ] f[j][i+j] f[j][i+j]是从左边(j)取的最大差值和从右边(i+j)取的最大差值,
定义 -f[j+1][i+j]+a[j] 是从左边取的最大差值,
定义 -f[j][i+j-1]+a[i+j] 是从右边取的最大差值。
所以 f [ j ] [ i + j ] = m a x ( − f [ j + 1 ] [ i + j ] + a [ j ] , − f [ j ] [ i + j − 1 ] + a [ i + j ] ) f[j][i+j]=max(-f[j+1][i+j]+a[j],-f[j][i+j-1]+a[i+j]) f[j][i+j]=max(f[j+1][i+j]+a[j],f[j][i+j1]+a[i+j])
题目分析完毕,直接上代码!!!

QWQ

qwq

QWQ
qwq

#include//懒
using namespace std;
int n,f[105][105],a[105],ans;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i],f[i][i]=a[i];//数组预处理
    for(int i=1;i<=n;i++)
        for(int j=1;j+i<=n;j++)
            f[j][j+i]=max(-f[j+1][j+i]+a[j],-f[j][i+j-1]+a[i+j]);//动态转移方程          
    cout<<f[1][n];//游戏结束
    return 0;
}

QWQ

你可能感兴趣的:(取数问题(区间dp入门))