旅行
【问题描述】
给定一个n 行m 列的字符矩阵,‘.’表示空地,‘X’表示障碍。移动的规则是:每秒钟可以上下
左右四个方向之一移动一格,不能进入障碍。计算:在空地中随机选择起点和终点(可以重合,此时
最短耗时为0),从起点移动到终点最短耗时的平均值。
每一行每一列至多有1 个障碍,并且障碍不在对角线方向相邻。以下矩阵是不合法的:
.X
X.
【输入】
每一行两个整数n,m。
接下来n 行,每行m 个字符‘.’或‘X’。在50%的数据中,保证每个字符都是‘.’。
【输出】
输出平均耗时,四舍五入保留4位小数。数据保证在[ans-10^7,ans+10^7]范围之内输出一致,
ans 是标准答案。
【输入样例】
2 2
..
.X
【输出样例】
0.8889
【Hint】
若有p 个空地,则随机选择起点到终点最短耗时的平均值为任意两点间曼哈顿距离之和除以空地
总数的平方:
这道题乍一眼看我是觉得很烦的,前一天我刚刚看了期望啊概率啊什么的然后第一眼看就以为要算期望什么 后来发现这道题 根本没这么麻烦
然后在考虑有过X的时候要怎么处理——>发现题目里说了“每一行每一列至多有1 个障碍,并且障碍不在对角线方向相邻。”
啊真的好简单啊
就是说如果起点和终点只要不在同一条直线或者同一条竖线上,就是简简单单求两点之间的曼哈顿距离:
(x1,y1) (x2,y2) 之间的曼哈顿距离是|x1-x2|+|y1-y2|
则任意两行之间的距离就是 (i行空地个数)(j行空地个数)(i-j)
如果在同一行或者同一列
则路途中遇到一个X就把步数加2
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define ll long long
const int N=1010;
const int INF=200000000;
using namespace std;
int a[N][N];
double ans=0,row[N],line[N],line1[N],row1[N],tot,n,m;
int main()
{
freopen("journey.in","r",stdin);
freopen("journey.out","w",stdout);
cin>>n>>m;
for (ll i=1; i<=n; i++)
line[i]=INF;
for (ll i=1; i<=m; i++)
row[i]=INF;
for (ll i=1; i<=n; i++)
{
for (ll j=1; j<=m; j++)
{
char c;
cin>>c;
if(c=='X') line[i]=j,row[j]=i,a[i][j]=1;
else a[i][j]=1,tot++,line1[i]++,row1[j]++;
}
}
for(ll i=1; i<=n; i++)
for (ll j=i; j<=n; j++)
ans+=(line1[i]*line1[j]*(j-i)*2.0)/tot/tot;
for(ll i=1; i<=m; i++)
for (ll j=i; j<=m; j++)
ans+=(row1[i]*row1[j]*(j-i)*2.0)/tot/tot;
for (ll i=1; i<=m; i++)
if(row[i]<INF)
{
double y=row[i]-1;
for(int j=i;j>1&&row[j-1]<row[j];j--)
y+=row[j-1]-1;
for(int j=i;j<m&&row[j+1]<row[j];j++)
y+=row[j+1]-1;
ans+=4.0*(n-row[i])*y/tot/tot;
}
for (ll i=1; i<=n; i++)
if(line[i]<INF)
{
double y=line[i]-1;
for(int j=i;j>1&&line[j-1]<line[j];j--)
y+=line[j-1]-1;
for(int j=i;j<n&&line[j+1]<line[j];j++)
y+=line[j+1]-1;
ans+=4.0*(m-line[i])*y/tot/tot;
}
printf("%.4lf\n",ans);
}