UVA - 10891 - Game of Sum - (区间DP)

题目链接:UVA - 10891 - Game of Sum - (区间DP)

题意:有n个数字的序列,有两个人A,B来玩游戏, 每个人每次可以从两端(左或右)中的任意一端取走一个或若干个数(获得价值为取走数之和), 但是他取走的方式一定要让他在游戏结束时价值尽量的高,最头疼的是两个人都很聪明,所以每一轮两人都将按照对自己最有利的方法去取数字,计算一下在游戏结束时,先取数的人A的价值与后取数人B的价值之差(不要求绝对值)。

题解全部来自下面的博客:

https://blog.csdn.net/nixinyis/article/details/50733202

https://blog.csdn.net/basementman/article/details/16905657

https://blog.csdn.net/tengfei461807914/article/details/50885531

解析

        有如下经典题目:个玩家A和B在玩一个取石子游戏,且每个石子都有它们各自的价值。在游戏中有这样一个规则:每次取一个石子必行从两端取,要么是最左端,要么是最右端,直到取完为止。两个玩家都非常聪明,他们每次都会去最优的结果。给他们N个石子,你能计算出玩家A,B各自的最后结果吗?假设总是玩家A先开局。

        因为分数总和是一定的,所以一个人的得分越高,另一个就越低。而且不管怎么取,游戏的状态始终是一段连续子序列。所以可以用数组best[i,j]来表示在由第i个到第j个元素组成的子序列时先手所能得到的最高分。因为两个人都是用最优策略,那么先手后手的问题可以随意定义一个就好。所以我们可以分析,另一个人在所能取得所有最优选择中得分最低的分数 m ,sum-m即为我的最高得分。

        对于这个经典问题,我们考虑best[i][j]表示开局者玩家Aij部分得到最大和,sum[i][j]表示从ij和,由于只能从两端取石子,要么有从最左端,要么从最右端。则有转移方程:

         best[i][j]=sum[i][j]-min(best[i][j-1],best[i+1][j]); 目标状态:best[1][n]


         那么推广到这题,可以从两端取连续的,我们同样稍改变下即可。在状态转移时,我们要枚举从左边和从右边取以及取多少个,这等价于枚举给对手剩下了怎么样的子序列,是(k,j)(i<k<=j),还是(k,j)(i<=k<j)。所以有


         best[i,j]=sum(i,j)-min{best[i+1,j],best[i+2,j]……,best[j,j],best[i,j-1],best[i,j-2]……,best[i,i],0}


         其中sum(i,j)是元素i到j的书之和,其中“0”表示取完所有的数。

         所以A的得分是d[1,n],B的得分是sum(1,n)-d[1,n],答案便是d[1,n]-(sum(1,n)-d[1,n])=2*d[1,n]-sum(1,n)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxN=105;

int sum[maxN],a[maxN];
int n,dp[maxN][maxN];
bool vis[maxN][maxN];

int fdp(int l,int r)
{
    if(vis[l][r]) return dp[l][r];
    vis[l][r]=true;
    int tmp=0;
    for(int k=l+1;k<=r;k++)
        tmp=min(tmp,fdp(k,r));
    for(int k=l;k<r;k++)
        tmp=min(tmp,fdp(l,k));
    dp[l][r]=sum[r]-sum[l-1]-tmp;
    return dp[l][r];
}

int main()
{
    while(scanf("%d",&n)&&n)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        memset(vis,false,sizeof(vis));
        int ans=2*fdp(1,n)-sum[n];
        printf("%d\n",ans);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/sdau20163942/article/details/80380108