题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4870
题意:有一个人打比赛开了两个账号 都是0分,每次他用分数低的那个号去比赛,输了-100,赢了+50,分数不可以低于0,给出赢得概率p,问到达1000分的期望次数。
思路:f[i][j]表示他的两个号分数分别为i,j(i<=j)达到1000分的期望次数,由于分数都是50的倍数,我们可以把数据范围缩小到0~20。
那么f[i][j] = p * f[ min(i+1,j) ][ max(i+1,j) ] + (1-p) * f[ min( max(i-2,0) , j ) ][ max( max(i-2,0) , j ) ]
然后对于f[19][19]再单独列一个式子,发现是高斯消元求f[0][0],直接上模板即可。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;
#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)
#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod 100000007
const int maxn = 250;
int n,m;
double A[maxn][maxn];
double p;
int pos[25][25];
int tot = 0;
void init()
{
tot = 0;
rep(i,0,19)
rep(j,i,19)
{
pos[i][j] = tot++;
}
}
void solve()
{
rep(i,0,tot-1)
{
int r = i;
rep(j,i+1,tot-1)
if ( fabs( A[j][i] ) > fabs( A[r][i] ) ) r = j;
if ( r != i ) rep(j,0,tot) swap( A[r][j] , A[i][j] );
Rrep(j,tot,i)
rep(k,i+1,tot-1)
A[k][j] -= A[k][i] / A[i][i] * A[i][j];
}
Rrep(i,tot-1,0)
{
rep(j,i+1,tot-1)
A[i][tot] -= A[j][tot] * A[i][j];
A[i][tot] /= A[i][i];
}
}
int main()
{
init();
while( scanf("%lf",&p) == 1 )
{
int n = -1;
Clean(A,0);
rep(i,0,19)
rep(j,i,19)
{
n++;
A[n][tot] = 1;
if ( i == 19 && j == 19 )
{
A[n][pos[19][19]] += 1;
A[n][pos[17][19]] += p-1;
}
else
{
A[n][pos[i][j]] += 1;
A[n][ pos[ min( i + 1 , j ) ][ max( i + 1 , j ) ] ] -= p;
A[n][ pos[ min( max( 0 , i - 2 ) , j ) ][ max( max( 0 , i - 2 ) , j ) ] ] += p-1;
}
}
solve();
printf("%0.7f\n",A[0][tot]);
}
return 0;
}