纸牌游戏-动态规划

题目描述

给定一个整形数组arr,代表不同的纸牌排成一条线,玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿,但是每个玩家每次只能拿走最左或最右的纸牌,玩家A和B都能看见纸牌的数值,且都绝顶聪明,返回最后获胜者的分数。

分析

base-case:当只剩一张牌时,先手获得此牌,后手得0。
先手者在选择两种方案后成为后手,挑选两种方案中最终得到分数最多的方案;
后手者在先手选择两种方案后成为先手,挑选此情景下能够得到最多的分数方案;

求解

#include <iostream>
#include <cmath>
using namespace std;
int n = 6;
//数组arr在L,R上做选择
int way1(int *arr, int L, int R);
//先手在数组arr在L,R上做选择,返回最大分数
int f1(int *arr, int L, int R);
//后手在数组arr在L,R上做选择,返回最大分数
int g1(int *arr, int L, int R);

int way2(int *arr, int L, int R);
int f2(int *arr, int L, int R, int fmap[][6], int gmap[][6]);
int g2(int *arr, int L, int R, int fmap[][6], int gmap[][6]);

int way3(int *arr, int N);
int main() {
    int arr[6] = {50, 100, 40, 20, 10, 40};
    cout << way1(arr, 0, 5) << endl;
    cout << way2(arr, 0, 5) << endl ;
    cout << way3(arr, 6) << endl ;
    return 0;
}
//暴力递归
int way1(int *arr, int L, int R) {
    return max(f1(arr, L, R), g1(arr, L, R));
}

int f1(int *arr, int L, int R) {
    if(L == R) {
        return arr[L];
    }
    int p1 = arr[L] + g1(arr, L + 1, R);
    int p2 = arr[R] + g1(arr, L, R - 1);
    return max(p1, p2);
}
int g1(int *arr, int L, int R) {
    if(L == R) {
        return 0;
    }
    int p1 = f1(arr, L + 1, R);
    int p2 = f1(arr, L, R - 1);
    return min(p1, p2);
}
//缓存
int way2(int *arr, int L, int R) {
    int fmap[6][6], gmap[6][6];
    for(int i = 0; i < 6; i++) {
        for(int j = 0; j < 6; j++) {
            fmap[i][j] = -1;
            gmap[i][j] = -1;
        }
    }
    return max(f2(arr, L, R, fmap, gmap), g2(arr, L, R, fmap, gmap));
}
int f2(int *arr, int L, int R, int fmap[][6], int gmap[][6]) {
    if(fmap[L][R] != -1) {
        return fmap[L][R];
    }
    int res = 0;

    if(L == R) {
        res = arr[L];
    } else {

        int p1 = arr[L] + g2(arr, L + 1, R, fmap, gmap);
        int p2 = arr[R] + g2(arr, L, R - 1, fmap, gmap);
        res = max(p1, p2);
    }
    fmap[L][R] = res;
    return res;
}
int g2(int *arr, int L, int R, int fmap[][6], int gmap[][6]) {
    if(gmap[L][R] != -1) {
        return gmap[L][R];
    }
    int res = 0;
    if(L != R) {
        int p1 = f2(arr, L + 1, R, fmap, gmap);
        int p2 = f2(arr, L, R - 1, fmap, gmap);
        res = min(p1, p2);
    }
    gmap[L][R] = res;
    return res;
}
//直接填表
int way3(int *arr, int N) {
    int fmap[6][6], gmap[6][6];
    for(int i = 0; i < 6; i++) {
        fmap[i][i] = arr[i];
        gmap[i][i] = 0;
    }
    for(int clo = 1; clo < 6; clo++) {
        int L = 0;
        int R = clo;
        while(R < 6) {
            cout << arr[L] + gmap[L + 1][R] << " " << arr[R] + gmap[L][R - 1] << endl;
            fmap[L][R] = max(arr[L] + gmap[L + 1][R], arr[R] + gmap[L][R - 1]);
            gmap[L][R] = min(fmap[L + 1][R], fmap[L][R - 1]);
            L++;
            R++;
        }
    }
    return max(fmap[0][5], gmap[0][5]);
}

posted @   sakuzeng  阅读(116)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示