http://acm.split.hdu.edu.cn/showproblem.php?pid=5725
可以知道一般情况下两点之间的距离是曼哈顿距离,当且仅当两点间每排都阶梯状的阻碍,是曼哈顿距离加2。
先算总和,每个点到另一个点分为两种,横向与纵向,横向算一次,纵向算一次。
在判断有多少点有横向阻挡或纵向阻挡。
#include<iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int Max=1005;
int x[Max],y[Max],blockx[Max],blocky[Max];
long long ans;
char a[Max][Max];
void calc(const int &n,int x[]){
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
ans+=(long long)(j-i)*x[i]*x[j];
}
}
}
int main(){
int T,m,n;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
getchar();
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(blockx,0,sizeof(blockx));
memset(blocky,0,sizeof(blocky));
for (int i = 1; i <= n; i++)
scanf("%s", a[i] + 1);
long long cnt = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (a[i][j] == '#')
x[i]++, y[j]++, cnt++;
else
blockx[i] = j, blocky[j] = i;
cnt*=cnt;
ans=0;
calc(n,x);
calc(m,y);
ans*=2;
int sum=0;
int tmp;
for(int i=1;i<=n;i++){
if(blockx[i-1]<blockx[i]){
sum+=blockx[i]-1;
}else if(!blockx[i]){
sum=0;
}else{
sum=blockx[i]-1;
}
tmp=m;
tmp-=blockx[i];
ans+=4*tmp*sum;
}
sum=0;
for(int i=n;i>=1;i--){
tmp=m;
if(blockx[i+1]<blockx[i]){
tmp-=blockx[i];
}
else{
tmp=0;
}
ans+=4*tmp*sum;
if(blockx[i+1]<blockx[i]){
sum+=blockx[i]-1;
}
else if(!blockx[i]){
sum=0;
}else{
sum=blockx[i]-1;
}
}
sum=0;
for(int i=1;i<=m;i++){
if(blocky[i-1]<blocky[i]){
sum+=blocky[i]-1;
}else if(!blocky[i]){
sum=0;
}else{
sum=blocky[i]-1;
}
tmp=n;
tmp-=blocky[i];
ans+=4*tmp*sum;
}
sum=0;
for(int i=m;i>=1;i--){
tmp=n;
if(blocky[i+1]<blocky[i]){
tmp-=blocky[i];
}
else{
tmp=0;
}
ans+=4*tmp*sum;
if(blocky[i+1]<blocky[i]){
sum+=blocky[i]-1;
}
else if(!blocky[i]){
sum=0;
}else{
sum=blocky[i]-1;
}
}
printf("%.4f\n",(double)ans/(double)cnt);
}
return 0;
}