题目是这样的,一条直线上有一些白色的圆。我们以三个圆为例,如下图:
O O O
现在让你把和黑色不相邻的圆涂成黑色。因为没有黑色,随意选择一个涂成黑色:
// 第一次:选第一个
* O O
// 第一次:选第二个
O * O
// 第一次:选第三个
O O *
我们的目标是涂涂涂,直到不能涂为止,最后输出黑色圆的个数的【数学期望】。
那我们把上面的情况补充完整:
// 第一次:选第一个
* O O
// 第二次:选第二个
* * O
// 第二次:选第三个
* O *
// 第一次:选第二个
O * O
// 第一次:选第三个
O O *
// 第二次:选第一个
* O *
// 第二次:选第二个
O * *
还要算数学期望,我把它加上去:
概率 黑圈数目
// 第一次:选第一个
* O O 1/3
// 第二次:选第二个
* * O 1/3 x 1/2 2
// 第二次:选第三个
* O * 1/3 x 1/2 2
// 第一次:选第二个
O * O 1/3 1
// 第一次:选第三个
O O * 1/3
// 第二次:选第一个
* O * 1/3 x 1/2 2
// 第二次:选第二个
O * * 1/3 x 1/2 2
期望为 E = (1/3)x(1/2)x2 + (1/3)x(1/2)x2 + (1/3)x1 + (1/3)x(1/2)x2 + (1/3)x(1/2)x2 = 5/3。
现在输入为一个数 N,求着 N 个白圆,涂黑后黑色圆的期望,比如当 N = 3,输出应为 1.6666666666666667。(只要你的结果相差不过 1e-6,就算对。)
费了九牛二虎之力,我终于把代码写好了:
#include <vector>
#include <cstdio>
using namespace std;
#define max(a,b) ((a)>(b)?(a):(b))
double dp(int n) {
vector<double> f(max(3,n+1));
f[0] = 0.0;
f[1] = 1.0;
f[2] = 1.0;
for (int i = 3; i <= n; ++i) {
double p = 0.0;
for (int j = 0; j <= i-3; ++j) {
p += (1.0 + f[j] + f[i - 3 - j]);
}
p += 2.0 * (1 + f[i - 2]);
f[i] = p/(double)i;
}
return f[n];
}
int main()
{
while(1 == scanf("%d", &n)) {
printf("%lf\n", dp(n));
}
}
好开心!这好像是我实战中第一次做对动态规划。(如果对的话。)
但是,在最后几分钟,我提交失败了。因为我特么把代码提交到第三题了……
为什么 AtCoder 这么蛋疼。我已经干了好几次这样的蠢事了。
“从小就粗心。”
“妈的傻逼不长记性。活该!”
不能开心了.