题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1204
设dp[i]为当前Speakless所拥有的的糖果数为i时的概率。
于是可以得到以下转移:
·赢了:概率为p*(1-q),会将p*(1-q)*dp[i]转移给dp[i+1]
·输了:概率为(1-p)*q,会将(1-p)*q*dp[i]转移给dp[i-1]
·平局:概率为p*1+(1-p)*(1-q),会将p*q+(1-p)*(1-q)转移给dp[i]
其中dp[0]和dp[n+m]为终点状态,不需要转移出去。
dp[n]为起点状态,视为将1.0转移给dp[n]。
看了一眼数据规律,懒得推公式了,直接高斯消元搞一波即可。
注意输出负0的情况。
代码:
#include <bits/stdc++.h>
using namespace std;
#define sfi(a) scanf("%d",&a)
#define sfd(a) scanf("%lf",&a)
#define sfl(a) scanf("%lld",&a)
#define sfs(a) scanf("%s",a)
#define rep(i,a,b) for(int i=int(a);i<int(b);++i)
#define dwn(i,b,a) for(int i=int(b-1);i>=int(a);--i)
#define mem(a,p) memset(a,p,sizeof(a))
typedef long long LL;
typedef unsigned UINT;
typedef unsigned long long ULL;
#define eps 0
#define MAXN 105
struct Gauss
{
double a[MAXN][MAXN]; //输入的矩阵
int n;
int res; //解空间的维数
bool l[MAXN]; //表示第i个解是否为自由元
double ans[MAXN]; //方程组的解
inline void init(int nn)
{
n=nn;
mem(a,0);
}
inline void update(int x,int y,double p) //令矩阵中的a[x][y]加上p
{
a[x][y]+=p;
}
inline void print() //调试用方法
{
rep(i,0,n)
{
rep(j,0,n+1)printf("%.3lf ",a[i][j]);
printf("\n");
}
printf("\n");
}
inline void solve() //生成解以及自由元判定
{
res=0;
int r=0;
rep(i,0,n)l[i]=false;
rep(i,0,n)
{
rep(j,r,n)if(fabs(a[j][i])>eps)
{
rep(k,i,n+1)swap(a[j][k],a[r][k]);
break;
}
if(fabs(a[r][i])<eps)
{
++res;
continue;
}
rep(j,0,n)if(j!=r&&fabs(a[j][i])>eps)
{
double tmp=a[j][i]/a[r][i];
rep(k,i,n+1)a[j][k]-=tmp*a[r][k];
}
l[i]=true,++r;
}
rep(i,0,n)
if(l[i])
rep(j,0,n)
if(fabs(a[j][i])>0)
ans[i]=a[j][n]/a[j][i];
}
}G;
int main()
{
int n,m;
while(sfi(n)==1)
{
sfi(m);
G.init(n+m+1);
G.update(n,n+m+1,-1);
double p,q;
sfd(p);
sfd(q);
rep(i,0,n+m+1)
{
G.update(i,i,-1.0);
if((i==0)||(i==n+m))continue;
G.update(i,i,p*q+(1.0-p)*(1.0-q));
G.update(i-1,i,(1-p)*q);
G.update(i+1,i,p*(1-q));
}
G.solve();
printf("%.2lf\n",G.ans[n+m]+1e-8);
}
}