Description
给定一个n行m列的字符矩阵,’.’代表空地,’X’代表障碍。移动的规则是:每秒钟以上下左右四个方向之一移动一格,不能进入障碍。
计算:在空地中随机选择起点和终点(可以重合,此时最短耗时为0),从起点移动到终点最短耗时的平均值。
每一行每一列至多有1个障碍,并且障碍不在对角线方向相邻。以下矩阵是不合法的:
.X
X.
Input
第一行两个整数n, m。
接下来n行,每行m个字符’.’或’X’。
Output
平均耗时,保留4位小数,四舍五入。
Sample Input
2 2
..
.X
Sample Output
0.8889
Data Constraint
Hint
2<=n,m<=1000
Solution
先解决前50%:所有两点间的曼哈顿距离和。
之间的曼哈顿距离等于。先计算前一部分的和。枚举两行i,j。观察到:随便从这两行中各取一个点,这两点的x坐标之差相同。因此,这两行所有点对的就等于:{第i行空地的数量}*{第j行空地的数量}*|i-j|*2。
计算的方法完全相同,略过。两部分答案相加,最后除以空地总数的平方,就得到最终答案。
要解决后50%,关键是要观察到,从A走到B的耗时,要么等于AB的曼哈顿距离,要么等于AB的曼哈顿距离+2。也就是至多绕行一次。这是由题目中的条件“不会有两个X封锁住对角线”保证的。
那么,怎样的点对需要绕行呢,观察:
...... ..X... ....X. .X.... ...... X..... ...... | ...... ..X... ....X. .X.... ...... X..... ...... | ...... ..X... ....X. .X.... .....X X..... ...... |
上图中红点到蓝点需要绕行。从直观上来看,一个X下方的点到这个X上方的点需要绕行。如果这个X右边一列(或者左边一列)包含X且本列X之上方,那么到这个X上方的点也需要绕行。横过来考虑是类似的。
根据以上规律,统计出需要+2的点对数加入答案即可AC本题。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define N 1010
using namespace std;
double ans;
ll tot,sum;
int n,m,x[N],y[N],dx[N],dy[N],t,k;
char c[N][N];
int main(){
scanf("%d%d\n",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%c",&c[i][j]);
if(c[i][j]=='X'){dx[j]=i;dy[i]=j;}
else{x[i]++;y[j]++;tot++;}
}
scanf("\n");
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
ans+=x[i]*x[j]*(abs(i-j))*2;
for(int i=1;i<=m;i++)
for(int j=i+1;j<=m;j++)
ans+=y[i]*y[j]*(abs(i-j))*2;
for(int i=1;i<=m;i++) if(dx[i]){
t=dx[i]-1;
k=i;
while(dx[k-1]&&dx[k-1]<dx[k]) t+=(dx[--k]-1);
k=i;
while(dx[k+1]&&dx[k+1]<dx[k]) t+=(dx[++k]-1);
ans+=t*(n-dx[i])<<2;
}
for(int i=1;i<=n;i++) if(dy[i]){
t=dy[i]-1;
k=i;
while(dy[k-1]&&dy[k-1]<dy[k]) t+=(dy[--k]-1);
k=i;
while(dy[k+1]&&dy[k+1]<dy[k]) t+=(dy[++k]-1);
ans+=t*(m-dy[i])<<2;
}
tot=tot*(tot-1)+tot;
printf("%.04lf",ans/tot);
return 0;
}
作者:zsjzliziyang
QQ:1634151125
转载及修改请注明
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/88806158