这题真的是太为难我了,在接触这题之前,没学过概率dp,没学过高斯消元,为了这道题目,我特地去看了那两个算法,然后才回过来做这题
题意:有两个账号,没次去分数低的去参加比赛,赢的概率是P,赢了之后加1(这里以50为一个单位),输的概率是(1-P),输了之后减2
思路:设 x , y 是当前两个分数,那么状态转移为f ( x , y ) = 1 + p( x1 , y1 ) + (1 - p)(x2 , y2),经分析得有210个状态,分别为f(0, 0......19)、f(1, 1......19)......、f(19,19)
然后设用未知数x,x1,x2........x210代替它们,得到210个未知数,然后利用状态转移构造210个方程,最后用guass消元解就可以了
为什么用guass消元解,而不用递推解?因为状态转移方程有后效行,用递推解可以, 但是很难推
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<time.h>
#include<math.h>
#define N 300
#define inf 0x7ffffff
#define eps 1e-9
#define pi acos(-1.0)
#define P system("pause")
using namespace std;
double p;
double A[N][N];
int c[30][30];
int tot = 0;
void init() {
memset(c, -1 ,sizeof(c));//??? 为什么一定要初始化为-1
for (int i = 0; i < 20; ++i) {
for (int j = 0; j <= i; ++j) {
c[i][j] = tot++;
}
}
//printf("len = %d\n", len);
}
void get_A()//求系数矩阵A
{
memset(A,0,sizeof(A));
int i,j;
int u,v;
for(i = 0; i <= 19; i++)
{
for(j = 0; j < i; j++)
{
u = c[i][j];
A[u][tot] = 1;
A[u][u] = 1;
v = c[i][max(0,j-2)];
A[u][v] -= (1.0-p);
v = c[i][j+1];
A[u][v] -= p;
}
u = c[i][i];
A[u][tot] = 1;
A[u][u] = 1;
v = c[i][max(0,j-2)];
A[u][v] -= 1-p;
v = c[i+1][i];
A[u][v] -= p;
}
}
void gauss_elimination(int n) //高斯消元解方程组
{
int i,j,k,r;
for(i = 0; i < n; i++)
{
r = i;
for(j = i+1; j < n; j++)
if( fabs(A[j][i]) > fabs(A[r][i]) )
r = j;
if(r != i)
for(j = 0; j <= n; j++)
swap(A[r][j],A[i][j]);
for(j = n; j >= i; j--)
for(k = i+1; k < n; k++)
A[k][j] -= A[k][i]/A[i][i]*A[i][j];
}
for(i = n-1; i >= 0; i--)
{
for(j = i+1; j < n; j++)
A[i][n] -= A[j][n]*A[i][j];
A[i][n] /= A[i][i];
}
}
int main()
{
ios::sync_with_stdio(false);
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
init();
while(cin>>p)
{
get_A();
gauss_elimination(210);
printf("%.6lf\n",A[0][210]);
}
return 0;
}