给定一个n行m列的字符矩阵。’.’代表空地,’X’代表障碍。
每秒钟可以往上下左右四个方向其中的一个移动一格(不能往障碍里面撞)。
起点和终点可以在空地里面随机选择(可以重合)。
求从起点移动到终点最短耗时的期望。
每一行、每一列至多有一个障碍。障碍不在对角线方向相邻。 。
第一行两个整数n, m。
接下来n行,每行m个字符’.’或’X’。
平均耗时。保留4位小数,四舍五入。
记
为空地数,
为障碍数
求
当然不可能枚举
解法有可能是枚举
然后利用之前计算的结果
两个点 之间的最短距离大于它们的曼哈顿距离当且仅当在 和 之间有一串墙,它们的 覆盖了 ~ , 覆盖了 ~ 。
会增加多少?
显然当且仅当障碍长成
u· · ·
x· · ·
· · · ·
· x· ·
· · · ·
· · x·
· · · ·
· · · x
· · · v
横过来也行,
之间距离大一点也行,
和
再上一点下一点也没关系,
多几列也好
然后用所有空地对的曼哈顿距离加上这些增加的部分就好了。
曼哈顿距离和是多少?
复杂的曼哈顿距离问题一般要分解为
方向和
方向的距离。
枚举行
。
枚举列
。
增加了多少?
求
~
间是否每个
都有一个障碍并且障碍的
单调递增或者递减。
记录一下具体是递增还是递减,障碍的
和
。
然后就可以计算纵方向距离多
的点对数量了。
同理。
考虑到同一行/列不能有两个障碍,所以
和
的答案不会有重复部分。
具体的实现从障碍来入手会方便得多。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<cstring>
#include<ctime>
using namespace std;
char ch=0;
double N,M,K=0;
double EmptyN[1005]={};
double EmptyM[1005]={};
double NPos[1005]={};
double MPos[1005]={};
bool Pt[1005][1005]={};
double Ans=0;
int main()
{
scanf("%lf%lf ",&N,&M);
for(int i=1;i<=N;++i)
{
while(ch!='.'&&ch!='X')ch=getchar();
for(int j=1;j<=M;++j)
{
if(ch=='X')Pt[i][j]=1,NPos[i]=j,MPos[j]=i;
else ++EmptyN[i],++EmptyM[j],++K;
ch=getchar();
}
}
for(int i=1;i<N;++i)
for(int j=i+1;j<=N;++j)
Ans+=2.0f*EmptyN[i]*EmptyN[j]*(j-i);
for(int i=1;i<M;++i)
for(int j=i+1;j<=M;++j)
Ans+=2.0f*EmptyM[i]*EmptyM[j]*(j-i);
for(int i=1;i<=N;++i)
{
if(!NPos[i])continue;
Ans+=4.0f*(NPos[i]-1.0)*(M-NPos[i]);
for(int j=i-1;j&&NPos[j]&&NPos[j]<NPos[j+1];--j)Ans+=4.0f*(NPos[j]-1.0)*(M-NPos[i]);
for(int j=i+1;j<=N&&NPos[j]&&NPos[j]<NPos[j-1];++j)Ans+=4.0f*(NPos[j]-1.0)*(M-NPos[i]);
}
for(int i=1;i<=M;++i)
{
if(!MPos[i])continue;
Ans+=4.0f*(MPos[i]-1.0)*(N-MPos[i]);
for(int j=i-1;j&&MPos[j]&&MPos[j]<MPos[j+1];--j)Ans+=4.0f*(MPos[j]-1.0)*(N-MPos[i]);
for(int j=i+1;j<=M&&MPos[j]&&MPos[j]<MPos[j-1];++j)Ans+=4.0f*(MPos[j]-1.0)*(N-MPos[i]);
}
printf("%.4f",Ans/K/K);
return 0;
}
数据生成器
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<sstream>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
ll GenRand(const ll Lim1,ll Lim2)
{
++Lim2;
ll ret=Lim1;
int t=0;
while(t<100)
{
if(rand()/(RAND_MAX+1.0)<0.1)break;
ret+=rand();
ret%=Lim2;
++t;
}
while(ret<Lim1)ret+=Lim1;
ret%=Lim2;
return ret;
}
int N,M;
bool Pd[1005]={},Px[1005]={};
stringstream ss;
int main( int argc, char *argv[] )
{
int seed=time(NULL);
if(argc > 1)//如果有参数
{
ss.clear();
ss<<argv[1];
ss>>seed;//把参数转换成整数赋值给seed
}
srand(seed);
N=GenRand(2,1000),M=GenRand(2,1000);
printf("%d %d\n",N,M);
for(int i=1;i<=N;++i)
{
for(int j=1;j<=M;++j)
{
if(rand()/(RAND_MAX+1.0)<0.5)printf(".");
else if(!Pd[i]&&!Px[j])printf("X"),Pd[i]=1,Px[j]=1;
}
printf("\n");
}
return 0;
}
对拍bat↓
@echo off
:loop
data_generator.exe %random% > data.in
std.exe < data.in > std.out
my.exe < data.in > my.out
fc my.out std.out
if not errorlevel 1 goto loop
pause
goto loop