uva 10891

本文解析了一个经典的博弈论DP题目,给出了详细的算法思路与C++实现代码。通过枚举状态,利用DP方法求解两人轮流取数游戏的第一人最大得分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自法力无边的厚白书。

题意:给出一个n个数的序列,两个人轮流从左端或右端开始取任意数。求第一人的数减去第二个人的最大值。

这一题,我们考虑从左边取还是从右边取,取多少个数。可以枚举每个状态。

dp[l[[r],表示从l到r,最大可以得到的数。它可以由dp[k][r], dp[l][m]得来,k = l  + 1---> r m = l ---- >r - 1。k和m相当于枚举取 1 -> n - 1个数的所有情况,也就是省下的数被取的情况,也就是另一个人取的最好情况。如果另一个人的最好情况大于0,那么就取完,如果小于0,那么就按照最优解的情况取。如何取完,需要m = 0。


#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100 + 5;
int dp[maxn][maxn], num[maxn], sum[maxn];
bool vis[maxn][maxn];
int DP(int l, int r)
{
    if(vis[l][r]) return dp[l][r];
    vis[l][r] = 1;
    int m = 0;//能使甚至取完所有数
    for(int k = l + 1; k <= r; k++)
        m = min(m, DP(k, r));
    for(int k = l; k < r; k++)
        m = min(m, DP(l, k));
    dp[l][r] = sum[r] - sum[l - 1] - m;
    //printf("%d %d %d\n", m, l, r);
    return dp[l][r];
}
int main()
{
    int n;
    sum[0] = 0;
    while(scanf("%d", &n) == 1 && n)
    {
        //memset(dp, 0, sizeof(dp));
        memset(vis, 0, sizeof(vis));
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &num[i]);
            sum[i] = sum[i - 1] + num[i];
        }
        printf("%d\n", 2 * DP(1, n) - sum[n]);//ans = DP(1, n) - ( sum[n] - DP(1, n) )
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值