纸牌游戏-动态规划
题目描述
给定一个整形数组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]);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律