题目
给定一个n行m列的字符矩阵,’.’代表空地,’X’代表障碍。移动的规则是:每秒钟以上下左右四个方向之一移动一格,不能进入障碍。
计算:在空地中随机选择起点和终点(可以重合,此时最短耗时为0),从起点移动到终点最短耗时的平均值。
每一行每一列至多有1个障碍,并且障碍不在对角线方向相邻。以下矩阵是不合法的:
.X
X.
分析
50%的数据,全都是空地,答案就是所有两点间的曼哈顿距离和。
很容易求, 第i行空地的数量∗第j行空地的数量∗|i−j|∗2
因为每一行每一列至多有1个障碍,并且障碍不在对角线方向相邻。得出从A走到B的耗时,要么等于AB的曼哈顿距离,要么等于AB的曼哈顿距离+2。
现在考虑什么情况下距离加二。
观察下图,规律显而易见,我就不多说了,

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=;
const int mo=;
const int N=;
using namespace std;
int a[N][N],n,m,sum,sx[N],sy[N],xx[N],xy[N];
double ans;
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
char c=getchar();
while(c!='.' && c!='X') c=getchar();
if(c=='.')
{
sx[i]++;
sy[j]++;
sum++;
}
else
{
xx[i]=j;
xy[j]=i;
}
}
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
ans+=abs(i-j)*sx[i]*sx[j]*/sum/sum;
for(int i=;i<=m;i++)
for(int j=;j<=m;j++)
ans+=abs(i-j)*sy[i]*sy[j]*/sum/sum;
for(int i=;i<=n;i++)
if(xx[i])
{
int mn=maxlongint,mx=-;
for(int j=i;j>=;j--)
{
if(xx[j]>mx && xx[j])
{
ans+=*(xx[i]-)*(m-xx[j])*/sum/sum;
mx=xx[j];
}
else
break;
}
for(int j=i;j>=;j--)
{
if(xx[j]<mn && xx[j])
{
ans+=*(xx[j]-)*(m-xx[i])*/sum/sum;
mn=xx[j];
}
else
break;
}
mn=xx[i],mx=xx[i];
for(int j=i+;j<=n;j++)
{
if(xx[j]>mx && xx[j])
{
ans+=*(xx[i]-)*(m-xx[j])*/sum/sum;
mx=xx[j];
}
else
break;
}
for(int j=i+;j<=n;j++)
{
if(xx[j]<mn && xx[j])
{
ans+=*(xx[j]-)*(m-xx[i])*/sum/sum;
mn=xx[j];
}
else
break;
}
}
for(int i=;i<=m;i++)
if(xy[i])
{
int mn=maxlongint,mx=-;
for(int j=i;j>=;j--)
{
if(xy[j]>mx && xy[j])
{
ans+=*(xy[i]-)*(n-xy[j])*/sum/sum;
mx=xy[j];
}
else
break;
}
for(int j=i;j>=;j--)
{
if(xy[j]<mn && xy[j])
{
ans+=*(xy[j]-)*(n-xy[i])*/sum/sum;
mn=xy[j];
}
else
break;
}
mn=xy[i],mx=xy[i];
for(int j=i+;j<=m;j++)
{
if(xy[j]>mx && xy[j])
{
ans+=*(xy[i]-)*(n-xy[j])*/sum/sum;
mx=xy[j];
}
else
break;
}
for(int j=i+;j<=m;j++)
{
if(xy[j]<mn && xy[j])
{
ans+=*(xy[j]-)*(n-xy[i])*/sum/sum;
mn=xy[j];
}
else
break;
}
}
printf("%.4lf",ans);
}