JZOJ3053. 【NOIP2012模拟10.25】旅行

来源:互联网 发布:钢结构cad软件 编辑:程序博客网 时间:2024/05/20 04:13

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

2<=n,m<=1000

分析

我们就先考虑没有X的情况,

那么答案很显然就是所有点两两的曼哈顿距离再除以点对数。

怎样快速计算它们的总和呢?

我们考虑整行整列的计算,
第i行到第j行的|xixj| 就等于第i行的空格数量×第j行的空格数量×|i-j|
列的计算方式相同。

现在再来考虑有X的情况,
先观察下面这张图片:
这里写图片描述
上图中红点到蓝点需要绕行。从直观上来看,一个X下方的点到这个X上方的点需要绕行。如果这个X右边一列(或者左边一列)包含X且本列X之上方,那么到这个X上方的点也需要绕行。根据以上规律,统计出需要+2的点对数加入答案即可AC本题。

code(c++)

#include <cstdio>#include <algorithm>#include <cstring>#include <string.h>#include <cmath>#include <math.h>using namespace std;int tot,t,k,f[1003],g[1003],n,m,x[1003],y[1003];double ans,sum;char ch;int main(){    freopen("2.in","r",stdin);    memset(f,0,sizeof(f));    memset(f,0,sizeof(g));    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    {        ch=getchar();        while((ch!='X')&&(ch!='.'))ch=getchar();        if(ch=='X'){f[i]++;g[1]++;tot++;x[i]=1;y[1]=i;}        for(int j=2;j<=m;j++)        {            ch=getchar();            if(ch=='X'){f[i]++;g[j]++;tot++;x[i]=j;y[j]=i;}        }    }    ans=0.00000000000;    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            ans+=(m-f[i])*(m-f[j])*abs(i-j);    for(int i=1;i<=m;i++)        for(int j=1;j<=m;j++)            ans+=(n-g[i])*(n-g[j])*abs(i-j);    for(int i=1;i<=n;i++)    {        if(!x[i])continue;        t=x[i]-1;        for(k=i-1;k&&(x[k])&&(x[k]<x[k+1]);k--)t+=x[k]-1;        for(k=i+1;(k<=n)&&(x[k])&&(x[k]<x[k-1]);k++)t+=x[k]-1;        ans+=t*(m-x[i])*4.0;    }    for(int i=1;i<=m;i++)    {        if(!y[i])continue;        t=y[i]-1;        for(k=i-1;k&&(y[k])&&(y[k]<y[k+1]);k--)t+=y[k]-1;        for(k=i+1;(k<=m)&&(y[k])&&(y[k]<y[k-1]);k++)t+=y[k]-1;        ans+=t*(n-y[i])*4.0;    }    sum=(n*m-tot);    printf("%.4lf\n",ans/sum/sum);}
1 0
原创粉丝点击