描述
在一个n行m列的矩阵中,’P’代表平缓的场地,’H’代表小山。人的起点是在某个P的空格中,在这个矩阵中移动的规则如下:
每秒钟人可以向上下左右四个方向中任何一个方向移动一格,但需要注意的是不能进入小山所在的格子。
现在在P中随机选择起点和终点(起点和终点是可以重合的,如果重合则耗时为0),请你计算从起点移动到终点的最短耗时的平均值。
给你的矩阵有一个特点,每一行每一列至多有1个H格,并且H格不在对角线方向相邻。即给你数据中不会存在以下矩阵格式的矩阵:
PH
HP
输入
输入数据格式:
第一行两个整数n, m。
接下来n行,每行m个字符’P’或’H’。
输出
输出平均耗时值,请保留4位小数,需要四舍五入。
输入样例 1
2 2 PH PP
输出样例 1
0.8889
输入样例 2
3 3 PPP HPP PPP
输出样例 2
1.8438
提示
2<=n,m<=1000
思路(详见代码)代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
const int oo=1e9;
int n,m;
double ans,p;
char a[N][N];
double b[N],c[N],d[N],e[N];
int main () {
//freopen("zdl.in","r",stdin);
//freopen("zdl.out","w",stdout);
scanf("%d%d\n",&n,&m);//一定要加\n!!!
for (int i=1; i<=n; i++)
d[i]=2147483647;
for (int i=1; i<=m; i++)
e[i]=2147483647;//memset只能赋0
for(int i=1; i<=n; i++) {//n行
for(int j=1; j<=m; j++) {//m列
scanf("%c",&a[i][j]);//输入每个字符
if(a[i][j]=='P') {
p++;//统计有多少个空地
b[i]++;//统计第i行有多少块空地
c[j]++;//统计第j列有多少块空地
} else {
d[i]=j;//记录障碍所在的位置
e[j]=i;
}
}
scanf("\n");//一定要加\n!!!
}
//先计算任意两点间的曼哈顿距离,这个距离分成两部分计算,
//下面这个是先计算任意两行中两个点之间的y2-y1的距离
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
ans+=b[i]*b[j]*abs(i-j);
//下面这个是先计算任意两列中两个点之间的x2-x1的距离
for(int i=1; i<=m; i++)
for(int j=1; j<=m; j++)
ans+=c[i]*c[j]*abs(i-j);
for(int i=1; i<=m; i++)
if(e[i]<2147483647) {//说明该列上有障碍 e[i]里保存的是该列上的障碍是在哪一行
int t=e[i]-1,k=i;//t是障碍所在行的上一行
while(k>1&&e[k-1]<e[k]) {//不是第一列,且左边那一列的障碍比当前列的障碍高
k--;//向左边列查找
t+=e[k]-1;//这一列上面有t个点,这些点到障碍所在位置的下面的所有的点距离都要加2
}
k=i;
while(k<m&&e[k+1]<e[k]) {//不是最后一列,且右边那一列的障碍比当前列的障碍高
k++;//向右边列查找
t+=e[k]-1;
}
ans+=(n-e[i])*t*4;//n-e[i]表示障碍下面有多少个点
}
for(int i=1; i<=n; i++)
if(d[i]<2147483647) {
int t=d[i]-1,k=i;
while(k>1&&d[k-1]<d[k]) {
k--;
t+=d[k]-1;
}
k=i;
while(k<n&&d[k+1]<d[k]) {
k++;
t+=d[k]-1;
}
ans+=(m-d[i])*t*4;
}
printf("%.4lf",ans/p/p);
return 0;
}