*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);
}