题目描述:
样例输入1:
2 2
..
.X
样例输出1:
0.888889
样例输入2:
3 3
…
.X.
…
样例输出2:
2.000000
数据规模:
对于 30% 的数据:n,m≤50;
对于 100% 的数据:2≤n,m≤10
题目分析:
1、不考虑障碍时,在矩阵里,最短距离就是行数差加列数差,可以对应到以起点、终点为顶点的矩形,路径可以移到边上,就是长宽之和。
2、考虑障碍,如果恰巧每一行都被挡住,由因为题目中性质1,所以只需绕一次,路径长度增加2。
3、所以总的只需把所有的加起来除以路径总数就能得答案。
附代码:
#include<iostream>
#include<cstring>
#include<string>
#include<ctime>
#include<queue>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
char s[1005];
int totx,n,m,liex[1005],hangx[1005];
long long work(int n,int m,int a[])//以行为例
{
long long res=0;
for(int i=1;i<=n;i++)//枚举每一行,起始行
{
long long sig=0,tot=m-a[i];
for(int j=1;j<=n;j++)//枚举每一行,终点行
if(a[j])//判断有障碍,则这一行会少一个可以终点的点
sig+=(m-1)*abs(i-j);//计算起始位置与终点位置的行差,再乘以终点的个数
else
sig+=m*abs(i-j);
if(a[i])//同理判断
res+=(m-1)*sig;//起始点的个数乘以到所有终点的路径和
else
res+=m*sig;
if(a[i])//判断是否存在连续的障碍
{
int l=i-1,r=i+1;
while(a[l]>a[l+1])//向上找,如果连续,则障碍后面的所有点都不可直接到达
tot+=m-a[l],l--;
while(a[r]>a[r-1])//同理
tot+=m-a[r],r++;
res+=2*2*tot*(a[i]-1);//从障碍左到障碍右不可直接到达,反过来也是,所以 *2,不可直接到达路径+2,所以整体*2
} // tot不可到达的总点数,a[i]-1起始点的个数
}
return res;
}
int main()
{
//freopen("length.in","r",stdin);
//freopen("length.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s);
for(int j=1;j<=m;j++)
if(s[j-1]=='X')
{
hangx[i]=j;
liex[j]=i;
totx++;
}
}
int tot=n*m-totx;//所有可以站人的点,tot*tot就是两人所有的随机站位
double ans=(work(n,m,hangx)+work(m,n,liex))*1.0/tot/tot;
printf("%0.6f\n",ans);
return 0;
}