USACO 3.3 A Game (game1)

本文介绍了一种利用动态规划解决博弈问题的方法。通过定义状态F[i][j]表示玩家在第i到j的子序列中能获得的最大分数,以及S[i][j]表示该子序列的总和。给出了状态转移方程,并展示了如何通过递归实现记忆化搜索来避免重复计算。

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

/*
博弈问题,可以使用动态规划求解。 状态定义:用F[i][j]表示第一个玩家先取时,
在第i到第j的子序列中能拿到的最高分;用S[i][j]表示第i到第j的子序列中所有数字的和;
用num[i]表示第1到第n的序列中第i个数。
边界条件:F[i][i]=num[i]
状态转移方程: F[i][j]=max{num[i]+S[i+1][j]-F[i+1][j],num[j]+S[i][j-1]-F[i][j-1]}
结果 p1=F[1][n]; p2=S[1][n]-F[1][n];
解析: num[i]+S[i+1][j]-F[i+1][j]表示的是,p1拿第i到第j最左边的数,
然后轮到p2在第i+1到第j的序列中先取,会剩下S[i+1][j]-F[i+1][j],这些归p1。
refer to byvoid;
Note both player 1 and player 2 want best reuslt;
*/
/*
ID: haolink1
PROG: game1
LANG: C++
*/

//#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;

const int MAX = 100;
int num[MAX];
int N = 0, ori = 0;
int dp[MAX][MAX];
ifstream fin("game1.in");
ofstream cout("game1.out");

int Sum(int a, int b){
    int sum = 0;
    for(int i = a; i <= b; i++){
        sum += num[i];
    }
    return sum;
}

inline int Max(int a, int b){
    return a >= b ? a : b;
}

int MemorizedDynamic(int a, int b){
   if(dp[a+1][b] == ori)
       dp[a+1][b] = MemorizedDynamic(a+1,b);
   if(dp[a][b-1] == ori)
       dp[a][b-1] = MemorizedDynamic(a,b-1);
   return Max(num[a]+Sum(a+1,b)-dp[a+1][b],num[b]+Sum(a,b-1)-dp[a][b-1]);
}

int main(){
    fin >> N;
    for(int i = 0; i < N; i++){
        fin >> num[i];
    }
    memset(dp,0xF,sizeof(dp));
    ori = dp[0][0];
    for(int i = 0; i < N; i++){
        dp[i][i] = num[i];
    }
    int ans = MemorizedDynamic(0,N-1);
    int ans2 = Sum(0,N-1)-ans;
    cout << ans << " " << ans2 << endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值