pro:给定N*M的矩阵,以及初始玩家位置。 规定玩家每次会等概率的向左走,向右走,向下走,原地不动,问走到最后一行的期望。保留4位小数。
sol:可以列出方程,高斯消元即可,发现是三角矩阵,O(N*M)----元素个数。 也可以用反复逼近答案。 反复做,dp[i][j]=(dp[i][j+1]+dp[i][j-1]+dp[i][j]+dp[i-1][j])/d[j]+1.0 为了使逼近效果更好,我每次先左一次,再右一次。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1010; double dp[maxn][maxn]; int d[maxn]; int main() { int N,M,x,y; scanf("%d%d%d%d",&N,&M,&x,&y); rep(i,1,M){ d[i]=2; if(i>1) d[i]++; if(i<M) d[i]++; } rep(i,x+1,N){ rep(t,1,20){ rep(j,1,M) dp[i][j]=(dp[i][j+1]+dp[i][j-1]+dp[i][j]+dp[i-1][j])/d[j]+1.0; for(int j=M;j>=1;j--) dp[i][j]=(dp[i][j+1]+dp[i][j-1]+dp[i][j]+dp[i-1][j])/d[j]+1.0; } } printf("%.10lf\n",dp[N][y]); return 0; }
高斯消元版本:
由于同行之间有后效性,所以我们在相邻层之间列方程,然后高斯消元。 即N次高斯消元,由于是上三角矩阵,所以每次高斯消元的复杂度是线性的:每行消去一个,然后倒着求解即可。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1010; double a[maxn][maxn],res[maxn],ans[maxn][maxn]; int N,M,X,Y; void Guass() { for(int R=N-1;R>=X;R--){ rep(i,1,M) res[i]=ans[R+1][i]; a[1][1]=a[M][M]=-2.0/3.0; a[1][2]=a[M][M-1]=1.0/3.0; res[1]=-ans[R+1][1]/3.0-1; res[M]=-ans[R+1][M]/3.0-1; rep(i,2,M-1){ a[i][i-1]=a[i][i+1]=1.0/4.0; a[i][i]=-3.0/4.0; res[i]=-ans[R+1][i]/4.0-1; } rep(i,1,M-1){ double t=a[i+1][i]/a[i][i]; a[i+1][i]-=t*a[i][i]; a[i+1][i+1]-=t*a[i][i+1]; //a[i+1][i+2]-=t*a[i][i+2]; 不知道为什么这行删去了也能AC res[i+1]-=t*res[i]; } ans[R][M]=res[M]/a[M][M]; for(int i=M-1;i>=1;i--){ ans[R][i]=(res[i]-a[i][i+1]*ans[R][i+1])/a[i][i]; } } } int main() { scanf("%d%d%d%d",&N,&M,&X,&Y); if(M==1){ printf("%.10lf\n",2.0*(N-X)); return 0; } Guass(); printf("%.10lf\n",ans[X][Y]); return 0; }