题意:有一个矩阵,算出从(0,0)到(n,m)的期望步数,每一个矩阵单元给出了向下,向右,向上,向左的概率,保证三者相加等于1,除了最后一个到达的位置相加全部等于0.
题解:附上传送门,看了后再说点自己的理解,首先得理解怎么算出期望步数,他是与自己走向别人的概率有关的东西,不是别人走向自己的概率,然后根据再根据期望公式列出来,就知道了是走向其他块的概率乘以其他块的期望步数,然后再加上相应的权值,最后将这个常量放到右边,每一个块都可以写出来,然后进行高斯消元,但是普通的高斯消元会T到死,然后进行优化,只要能化为一个上三角矩阵,这样普通写,大概能有2s。
附上代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=51;
const int maxm=100805;
int n,m;
double p[maxn][maxn][4];
double a[maxn*maxn][maxn*maxn],b[maxn*maxn];
int dir[][2]={{1,0},{0,1},{-1,0},{0,-1}};
int r,c;
double gaosi()
{
for(int i=r-1;i>=0;i--){
for(int j=i-1;j>=0;j--){
double temp=a[j][i]/a[i][i];
if(temp==0){
continue;
}
for(int k=i;k>=0;k--){
a[j][k]-=a[i][k]*temp;
}
b[j]-=b[i]*temp;
}
}
return b[0]/a[0][0];
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF&&n&&m){
for(int k=0;k<4;k++){
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%lf",&p[i][j][k]);
}
}
}
r=n*m;
memset(a,0,sizeof(a));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
int id=i*m+j;
b[id]=a[id][id]=1.0;
if(i==n-1&&j==m-1){
a[id][id]=1.0;
continue;
}
for(int k=0;k<4;k++){
int x=i+dir[k][0];
int y=j+dir[k][1];
if(x<0||x>=n||y<0||y>=m){
continue;
}
a[id][x*m+y]=-p[i][j][k];
}
}
}
b[r-1]=0;
printf("%.7lf\n",gaosi());
}
return 0;
}
第二种优化,就是一行一行消,论文中有相应的介绍,因为其他地方都是0,跑完大概860ms
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=51;
const int maxm=100805;
int n,m;
double p[maxn][maxn][4];
double a[maxn*maxn][maxn*maxn],b[maxn*maxn];
int dir[][2]={{1,0},{0,1},{-1,0},{0,-1}};
int r,c;
double gaosi()
{
for(int i=r-1;i>=0;i--){
int down=max(0,i-m);
for(int j=i-1;j>=down;j--){
double temp=a[j][i]/a[i][i];
for(int k=i;k>=down;k--){
a[j][k]-=a[i][k]*temp;
}
b[j]-=b[i]*temp;
}
}
return b[0]/a[0][0];
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF&&n&&m){
for(int k=0;k<4;k++){
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%lf",&p[i][j][k]);
}
}
}
r=n*m;
memset(a,0,sizeof(a));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
int id=i*m+j;
b[id]=a[id][id]=1.0;
if(i==n-1&&j==m-1){
a[id][id]=1.0;
continue;
}
for(int k=0;k<4;k++){
int x=i+dir[k][0];
int y=j+dir[k][1];
if(x<0||x>=n||y<0||y>=m){
continue;
}
a[id][x*m+y]=-p[i][j][k];
}
}
}
b[r-1]=0;
printf("%.7lf\n",gaosi());
}
return 0;
}