NOIP模拟 Game

题意:

有n个带权球,A和B两个人,A先手拿球,一开始可以拿1个或2个,如果前一个人拿了k个,那么当前的这个人只能那k或k+1个,如果当前剩余的球不足,那么剩下的球都作废,游戏结束。假设两个人都是聪明人,每个人都会想方设法设获得比对方更多的球。问A最多能B多拿多少。

分析:

可以将先手取1n的最优值看做一个问题,先手取2n又是一个新的子问题,这样递归下去,便可求解。
(f[i][k])表示从第i个开始,可以取k或k+1个,先手取比对方多出的最大值(可能是负数)。
考虑用记忆化搜索:
(f[i][k] = max(sum[i, i + k - 1] + f[i + k][k], sum[i, i + k] + f[i + k + 1][k + 1]))
注意递归边界及条件。

记忆化搜索的常数极大,考试时明明写的正解都被卡飞了,改了一个小小的初始化就A了,还是多写递推吧。

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<ctime>
#include<vector>
#include<queue>
#include<map>
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        T i = 0, f = 1; char ch = getchar();
        for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
        if(ch == '-') f = -1, ch = getchar();
        for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
        x = i * f;
    }
    template<typename T>
    inline void wr(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
}using namespace IO;

const int N = 2e4 + 50, OO = 2e9 + 5;
int T, n;
int a[N], sum[N];
typedef pair<int,int> P;
int f[N][250];
int vst[N][250], vt;

inline void  chkmx(int &x, const int &y){
    if(x < y) x = y;
}

inline int F(int x, int k){
//	if(f[x][k] != -OO) return f[x][k];
    if(vst[x][k] == vt) return f[x][k];
    vst[x][k] = vt;
    if(x > n - k + 1)
		return f[x][k] = 0;
    int ret = -OO;
    if(x <= n - (k + 1) + 1)
        chkmx(ret, sum[x + k] - sum[x - 1] - F(x + k + 1, k + 1));
    chkmx(ret, sum[x + k - 1] - sum[x - 1] - F(x + k, k));
    return f[x][k] = ret;
}

int main(){
    freopen("game.in", "r", stdin);
    freopen("game.out", "w", stdout);
    read(T);
    while(T--){
        read(n);
        sum[0] = 0;
        for(register int i = 1; i <= n; i++) read(a[i]), sum[i] = sum[i - 1] + a[i];
//        for(register int i = 1; i <= n; i++)
//            for(register int j = 0; j <= 200; j++)
//                f[i][j] = -OO;
        vt++;
        wr(F(1, 1));
        putchar('
');
    }
    return 0;
}

原文地址:https://www.cnblogs.com/CzYoL/p/7756383.html