您的位置:首页 > 其它

纸牌博弈问题 动态规划

2017-12-21 21:05 423 查看
1、问题描述:来源《算法与数据结构最优解》左程云

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

2、输入输出

输入输出:arr=[1,2,100,4]。开始时玩家A只能拿走1或4.如果玩家A拿走1,则排列变成[2,100,4],B可以取走2或者4,如果玩家A拿走4,则排列变成[1,2,100],接下来玩家B可以拿走1或者100,然后继续轮到玩家A。玩家A绝顶聪明,所以不会拿4,因为那样100会被B拿走,玩家A选择1,这样100就属于A了,最终返回101.

3、问题解析

1)这个问题和表达式期望结果数目类似,两个状态互相对立,互相依赖。

2)这两个状态是arr从 i 到 j 聪明绝顶的人先拿所得的分数f[i][j],和聪明绝顶的人后拿所得的分数s[i][j]。

3)接下来是递推式:先拿的人A有两种选择,如果拿arr[i],那么对于arr[i+1]到arr[j]就成了后拿;如果拿arr[j]那么对于arr[i]到arr[j-1]就成了后拿,选择最优的;在A拿完之后,B成了先拿的人,但是A会给B剩下一种最差的方案,也就是在f[i+1][j]和f[i][j-1]中选择最小的一个。

4、代码如下

#include<iostream>
#include<vector>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
using namespace std;
int getResult(vector<int>, int);
int main() {

int n;
cin >> n;
vector<int> arr(n);
for (int i = 0; i < n; ++i) {
cin >> arr[i];
}
cout << getResult(arr,n) << endl;
}
int getResult(vector<int>arr,int n) {
int i, j;
vector<vector<int>> f(n, vector<int>(n)), s(n, vector<int>(n));//f[i][j]代表绝顶聪明的人从arr[i]到arr[j]先拿可以得到的分数,s[i][j]代表后拿可以得到的分数
//对f和s赋值
for (j = 0; j < n; ++j) {
f[j][j] = arr[j];//i==j,先拿的人只有一种选择,就是arr[i]
s[j][j] = 0;//i==j,后拿的人没有纸牌可拿
for (i =j - 1; i >= 0; --i) {//计算的方向是每一列从下往上,先计算行,后计算列
f[i][j] = max(arr[i] + s[i + 1][j], arr[j] + s[i][j - 1]);//先拿的人有两种选择,如果拿arr[i],那么对于arr[i+1]到arr[j]就成了后拿;如果拿arr[j]那么对于arr[i]到arr[j-1]就成了后拿,选择最优的。
s[i][j] = min(f[i + 1][j], f[i][j - 1]);//在A拿完之后,B成了先拿的人,但是A会给B剩下一种最差的方案,也就是在f[i+1][j]和f[i][j-1]中选择最小的一个
}
}
//返回f和s中较大的一个
return max(f[0][n - 1], s[0][n - 1]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: