题目要求:
排成一条线的纸牌博弈问题
给定一个整形数组arr,代表数值不同的纸牌排成一条线。玩家A和玩家B依次拿走每张纸牌,规定玩家A先拿,玩家B后拿,但每个玩家每次只能拿走最左或最右的纸牌,玩家A和玩家B都绝顶聪明,请返回最后获胜者的分数。
解题分析:
假设数组int arr[n],设函数f(i,j)表示数列a[i…j]序列被“先手拿”最终得分;假设g(i,j)表示数列a[i…j]序列“后手拿”最终得分。
分析可知f(i,j) = max{g(i+1,j)+arr[i], g(i,j-1)+arr[j]};
g(i,j) = min{f(i+1,j), f(i,j-1)}; (说明:因为双方都绝顶聪明,所以假设A先手,B后手,A一定把两种情况中小的留给后手选手)
在分析完题目后,我们发现这是一个递归问题,可以暴力递归直接解这个问题,代码如下:
class Game {
public:
Game(std::vector<int> &ivecArray) : m_ivecArr(ivecArray) {};
~Game() {};
int getScore();
int f(int i, int j);
int g(int i, int j);
private:
std::vector<int> &m_ivecArr;
};
int Game::f(int i, int j) {
if (i == j) {
return m_ivecArr[i];
}
return max<int>( (m_ivecArr[i] + g(i+1, j)), (m_ivecArr[j] + g(i, j-1)) );
}
int Game::g(int i, int j) {
if (i == j) {
return 0;
}
return min<int>( f(i+1, j), g(i, j-1) );
}
int Game::getScore() {
if (ivecArr.empty()) {
return 0;
}
return max<int>(f(0,(ivecArr.size()-1)) , g(0,ivecArr.size()-1));
}
然后我们分析一下时间复杂度和空间复杂度。
——————-假设数组长度为N——————————
时间复杂度:O(2ˆN)——因为每个递归的递推式都是:左1=右2
空间复杂度:O(N);
于是想到了动态规划打表,把重复的计算存起来,代码如下:
int getScore(std::vector<int> &ivecArr) {
if (ivecArr.empty()) {
return 0;
}
// 空间复杂度O(Nˆ2)
int length = (int)(ivecArr.size() -1);
int fScore[length+1][length+1];
int gScore[length+1][length+1];
for (int i = 0; i <= length; i++) {
for (int j = 0; j <=length; j++) {
fScore[i][j] = 0;
gScore[i][j] = 0;
}
}
// 时间复杂度O(Nˆ2)
for (int j = 0; j <= length; ++j) {
fScore[j][j] = ivecArr[j];
for (int i = j-1; i >= 0; i--) {
fScore[i][j] = max<int>((gScore[i+1][j] + ivecArr[i]), (gScore[i][j-1] + ivecArr[j]));
gScore[i][j] = min<int>(fScore[i+1][j] , fScore[i][j-1]);
}
}
return max<int>(fScore[0][length],gScore[0][length]);
}
int main(void) {
int iarray[] = {1,100,2};
size_t size = sizeof(iarray) / sizeof(int);
vector<int> ivecArray(iarray,iarray+size);
cout<<"Test case 1 :socre = "<<getScore(ivecArray)<<endl;
}
此方法的时间复杂度O(Nˆ2)—两次遍历;
空间复杂度O(Nˆ2)—打表占的空间;
OKay,完整源码附在下面:
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#ifdef _METHOLD_1_
class Game {
public:
Game(std::vector<int> &ivecArray) : m_ivecArr(ivecArray) {};
~Game() {};
int getScore();
int f(int i, int j);
int g(int i, int j);
private:
std::vector<int> &m_ivecArr;
};
int Game::f(int i, int j) {
if (i == j) {
return m_ivecArr[i];
}
return max<int>( (m_ivecArr[i] + g(i+1, j)), (m_ivecArr[j] + g(i, j-1)) );
}
int Game::g(int i, int j) {
if (i == j) {
return 0;
}
return min<int>( f(i+1, j), g(i, j-1) );
}
int Game::getScore() {
if (ivecArr.empty()) {
return 0;
}
return max<int>(f(0,(ivecArr.size()-1)) , g(0,ivecArr.size()-1));
}
#else
int getScore(std::vector<int> &ivecArr) {
if (ivecArr.empty()) {
return 0;
}
int length = (int)(ivecArr.size() -1);
int fScore[length+1][length+1];
int gScore[length+1][length+1];
for (int i = 0; i <= length; i++) {
for (int j = 0; j <=length; j++) {
fScore[i][j] = 0;
gScore[i][j] = 0;
}
}
for (int j = 0; j <= length; ++j) {
fScore[j][j] = ivecArr[j];
for (int i = j-1; i >= 0; i--) {
fScore[i][j] = max<int>((gScore[i+1][j] + ivecArr[i]), (gScore[i][j-1] + ivecArr[j]));
gScore[i][j] = min<int>(fScore[i+1][j] , fScore[i][j-1]);
}
}
return max<int>(fScore[0][length],gScore[0][length]);
}
#endif
int main(void) {
int iarray[] = {1,100,2};
size_t size = sizeof(iarray) / sizeof(int);
vector<int> ivecArray(iarray,iarray+size);
cout<<"Test case 1 :socre = "<<getScore(ivecArray)<<endl;
}
路漫漫其修远兮,吾将上下…