您的位置:首页 > 其它

排成一条线的纸牌博弈问题

2017-08-12 14:35 190 查看
/***************************************************************************

 *description:排成一条线的纸牌博弈问题

 *            给定一个整型数组arr,代表数值不同的纸牌排成一条线

 *            玩家A和玩家B依次拿走每张纸牌,规定A先拿。

 *            每个玩家每次只能拿走最左或最右的纸牌。

 *            返回最后获胜者的分数。

 *            例:arr=[1,2,100,4]

 *                玩家A拿走1,然后B拿走2或4,A再拿100,返回101
 **************************************************************************/

#include<iostream>
#include<vector>
using namespace std;

//方法1:暴力递归。时间复杂度O(2^N),空间复杂度O(N)
//定义函数f[i][j]表示arr[i...j]被绝顶聪明的人先拿得到的分数。
// i==j时,就一张牌,直接返回arr[i];否则该人只能拿arr[i]或arr[j]:
// 拿arr[i],剩下的arr[i+1...j]他变成后拿的人;拿arr[j],剩下的arr[i...j-1]他变成后拿的人;
// 所以函数返回max(arr[i]+s[i+1][j], arr[j]+s[i][j-1])
//定义函数s[i][j]表示arr[i...j]被绝顶聪明的人后拿得到的分数。
// i==j时,先拿的拿走,后拿的没有,返回0;否则
// 先拿的人可能拿走arr[i]或arr[j].由于先拿的也是绝顶聪明
// 所以函数返回min(f[i+1][j],f[i][j-1])
int f(vector<int> arr, int left, int right);
int s(vector<int> arr, int left, int right)
{
if (left == right)
return 0;
return min(f(arr,left+1,right),f(arr,left,right-1));
}
int f(vector<int> arr, int left, int right)
{
if (left == right)
return arr[left];
return max(arr[left]+s(arr,left+1,right), arr[right]+s(arr,left,right-1));
}

int winerScore_1(vector<int> arr)
{
if (arr.size() == 0)
return 0;

return max(f(arr, 0, arr.size()-1), s(arr, 0, arr.size()-1));
}
//方法2:动态规划。时间复杂度O(N^2),空间复杂度O(N^2)

int winerScore_2(vector<int> arr)
{
if (arr.size() == 0)
return 0;

int N = arr.size();

vector<vector<int>> s(N,N);
vector<vector<int>> f(N,N);
f[0][0] = arr[0];
s[0][0] = 0;
for (int i = N-1; i >= 0; i--)
{
f[i][i] = arr[i];
s[i][i] = 0;
for (int j = i+1; j < N; j++)
{
f[i][j] = max(arr[i]+s[i+1][j], arr[j]+s[i][j-1]);
s[i][j] = min(f[i+1][j], f[i][j-1]);
}
}
return max(s[0][N-1], f[0][N-1]);
}
int main()
{
vector<int> arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(100);
arr.push_back(4);
cout << winerScore_2(arr);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: