#include <cstdio>
#include <cstring>
#include <cmath>
const double eps=1e-7;
double dp[20];
double p;
int main() {
int i,j;
double ans;
while (scanf("%lf",&p)!=EOF) {
dp[0]=1/p;
dp[1]=(1+(1-p)*dp[0])/p;
for (i=2;i<20;i++) {
dp[i]=(1+(1-p)*(dp[i-2]+dp[i-1]))/p;
}
ans=dp[19];
for (i=0;i<19;i++) {
ans+=dp[i]+dp[i];
}
printf("%.8lf\n",ans);
}
return 0;
}
先贴代码。。。高斯消元,dp[i][j]代表i>=j时候距离目标期望多少步。。然后。。。发现是个等式。。。解方程
dp[i][j] = p*(dp[i][j+1])+(1-p)*(dp[i][j-2])+1
当i == j 时候注意变i
高斯消元
其实还有更机智的做法
dp[i]表示第i分到第i+1分 的期望 dp[i]=1+p*0+(1-p)*(dp[i-2]+dp[i-1]+dp[i])
然后变换一下式子直接转移就行。。。O(20)复杂度
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const double eps = 1e-9;
const int N = 305;
double p , a[N][N];
int mark[25][25];
double solve() {
for (int i = 0; i < 210; i ++) {
int k = i;
for (; k < 210; k++)
if (fabs(a[k][i]) > eps) break;
for (int j = 0; j <= 210; j++)
swap(a[i][j], a[k][j]);
for (int j = 0; j < 210; j++) {
if (i == j) continue;
if (fabs(a[j][i]) > eps) {
double x = a[j][i] / a[i][i];
for (int k = i; k <= 210; k++) {
a[j][k] -= a[i][k] * x;
}
}
}
}
return a[0][210] / a[0][0];
}
void build()
{
memset( a , 0 , sizeof ( a ) );
for (int i = 0 ; i < 20 ; i ++)
{
for (int j = 0 ; j < i ; j ++)
{
int u = mark[i][j];
a[u][u] = 1;
a[u][210] = 1;
int v = mark[i][max(0,j-2)];
a[u][v] -= ( 1 - p );
v = mark[i][j+1];
a[u][v] -= p;
}
int u = mark[i][i];
a[u][u]=1;
a[u][210] = 1;
int v = mark[i][max(0,i-2)];
a[u][v] -= (1-p);
v = mark[i+1][i];
a[u][v] -= p;
}
}
int main()
{
int cnt = 0 ;
memset( mark , -1 , sizeof ( mark ) );
for ( int i = 0 ; i < 20 ; i ++ )
{
for ( int j = 0 ; j <= i ; j ++ )
{
mark[i][j] = cnt++;
}
}
while ( scanf("%lf" , &p) != EOF )
{
build();
printf("%.6lf\n" , solve());
}
return 0;
}