1 题目描述
2 递归解法
轮到甲抽牌的时候,下一轮再轮到甲抽牌的时候,四种可能:
- 甲上乙上
- 甲上乙下
- 甲下乙上
- 甲下乙下
其实在遍历一颗四叉树,树的高度log2(n),复杂度应该是2^n。
2.1 实例
输入:
5 10 20
1 3 4 5 13
递归过程就是:遍历一颗四叉树
2.2 代码实现
int* array;
double p;
double q;
double g_score;
//四叉树
void run(int begin, int end, int sum/*甲已有的牌的和*/, double Probability/*已累计的概率*/)
{
if (end - begin <= 1) {
g_score += (sum + array[begin]) * Probability* p;//甲上
g_score += (sum + array[end]) * Probability* (1 - p);//甲下
return;
}
//甲上乙上
run(begin + 2, end, sum + array[begin], Probability* p * q);
//甲上乙下
run(begin + 1, end - 1, sum + array[begin], Probability* p * (1 - q));
//甲下乙上
run(begin + 1, end - 1, sum + array[end], Probability* (1 - p) * q);
//甲下乙下
run(begin, end - 2, sum + array[end], Probability* (1 - p) * (1 - q));
}
int main()
{
int n;
int pint, qint;
cin >> n >> pint >> qint;
p = (double)pint / 100.0;
q = (double)qint / 100.0;
array = (int*)malloc(sizeof(int)* n);
for (int i = 0; i<n; i++) {
cin >> array[i];
}
run(0, n - 1, 0, 1);
printf("%.3f\n", g_score);
return 0;
}
2.3 问题
复杂度太大,O(2^n),指数级。
3动态规划解法
3.1 子问题界定和计算顺序
子问题
F(begin , end):当牌只有array[ begin ], array[begin+1], … array[ end ],甲的得分期望。
如何计算F(begin,end)呢?划分成四个子问题:
- p * q * (array[begin] + F[begin + 2][end]) //甲上乙上
- p * (1 - q) * (array[begin] + F[begin + 1][end - 1]) //甲上乙下
- (1 - p) * q * (array[end] + F[begin + 1][end - 1]) //甲下乙上
- (1 - p) * (1 - q) * (array[end] + F[begin][end - 2]) //甲下乙下
将这四种可能相加,即可。
计算顺序
见下面的实例
3.2 实例
输入:
5 10 20
1 3 4 5 13
3.2.1 计算顺序
3.3 代码实现
#include <iostream>
#include <algorithm>
using namespace std;
double** dp;
int* array;
double p;
double q;
void func(int begin, int end)
{
if (begin == end) {//一个元素
dp[begin][end] = array[begin];
return;
}
else if (end - begin == 1) {//两个元素
dp[begin][end] = p * array[begin] + (1 - p) * array[end];
return;
}
//多个元素
dp[begin][end] =
p*q*(array[begin] + dp[begin + 2][end]) + //甲上乙上
p*(1 - q)*(array[begin] + dp[begin + 1][end - 1]) + //甲上乙下
(1 - p)*q*(array[end] + dp[begin + 1][end - 1]) + //甲下乙上
(1 - p)*(1 - q)*(array[end] + dp[begin][end - 2]); //甲下乙下
}
int main()
{
int n;
int pint, qint;
cin >> n >> pint >> qint;
p = (double)pint / 100.0;
q = (double)qint / 100.0;
//分配结果dp
dp = (double**)malloc(sizeof(double*)* n);
for (int i = 0; i < n; i++) {
dp[i] = (double*)malloc(sizeof(double)* n);
}
//分配数组
array = (int*)malloc(sizeof(int)* n);
for (int i = 0; i<n; i++) {
cin >> array[i];
}
//注意计算顺序
for (int gap = 0; gap < n; gap++) {
for (int i = 0; i < n; i++) {
int j = i + gap;
if (j < n) {
func(i, j);
} else {
break;
}
}
}
printf("%.3f", dp[0][n - 1]);
return 0;
}
3.4 复杂度
只需要计算表格的一半即可,O(1/2 * n^2)。