Description
给定一个n行m列的字符矩阵,’.’代表空地,’X’代表障碍。移动的规则是:每秒钟以上下左右四个方向之一移动一格,不能进入障碍。
计算:在空地中随机选择起点和终点(可以重合,此时最短耗时为0),从起点移动到终点最短耗时的平均值。
每一行每一列至多有1个障碍,并且障碍不在对角线方向相邻。以下矩阵是不合法的:
.X
X.
Solution
先计算出所有点互相到达的曼哈顿距离和: ∑|x1−x2|+|y1−y2|
这两部分是可以拆开来算的:第
i
行(列)的空地数×第
然后我们可以通过50%了。
为什么不是100%?因为有些情况要绕路。
然后我们看,如果第
行的计算也是如此。
那么绕行的代价是什么呢?
假如有两点A,B,A到B需要绕行,因为X不在对角线方向相邻,所以至多绕行一次,所以代价就是两点曼哈顿距离+2,于是 n2 统计要绕行的对数就行了。
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 1010
using namespace std;
int map[N][N];
int p[N],q[N];
int r[N],c[N];
char s[N];
int main()
{
int n,m;
cin>>n>>m;
double num=0;
fo(i,1,n)
{
scanf("%s",s+1);
fo(j,1,m)
{
map[i][j]=(s[j]=='X');
p[i]+=!map[i][j];
num+=!map[i][j];
if(map[i][j]) c[j]=i;
else if(!c[j]) c[j]=N;
if(map[i][j]) r[i]=j;
else if(!r[i]) r[i]=N;
}
}
c[0]=c[m+1]=N;
fo(j,1,m)
fo(i,1,n) q[j]+=!map[i][j];
r[0]=r[n+1]=N;
double ans=0;
fo(i,1,n-1)
fo(j,i+1,n) ans+=p[i]*p[j]*(j-i);
fo(i,1,m-1)
fo(j,i+1,m) ans+=q[i]*q[j]*(j-i);
fo(i,1,n)
if(r[i]!=N)
{
ans+=(r[i]-1)*1.0*(m-r[i])*2;
fo(j,i+1,n)
if(r[j]<r[j-1]) ans+=(r[j]-1)*(m-r[i])*2;
else break;
fd(j,i-1,1)
if(r[j]<r[j+1]) ans+=(r[j]-1)*(m-r[i])*2;
else break;
}
fo(i,1,m)
if(c[i]!=N)
{
ans+=(c[i]-1)*(n-c[i])*2;
fo(j,i+1,m)
if(c[j]<c[j-1]) ans+=(c[j]-1)*(n-c[i])*2;
else break;
fd(j,i-1,1)
if(c[j]<c[j+1]) ans+=(c[j]-1)*(n-c[i])*2;
else break;
}
printf("%.4lf",ans*2/(num*num));
}