题意
给定一个n行m列的字符矩阵,.代表空地,X代表障碍。移动的规则是:每秒钟以上下左右四个方向之一移动一格,不能进入障碍。
计算:在空地中随机选择起点和终点(可以重合,此时最短耗时为0),从起点移动到终点最短耗时的平均值。
每一行每一列至多有1个障碍,并且障碍不在对角线方向相邻。以下矩阵是不合法的:
.X
X.
思路
可以发现以下结论:
....
..X.
....
.X..
....
X...
....
如图,点(5,1)经过X上方的点都要绕路。
即向上或向下的一段连续的X会使得在这些X上(下)的点都要绕路(使得原距离+2)。
对于横着的也如此考虑。
得出算法:先不考虑障碍算距离,再加上绕路的距离即可。
对于不考虑障碍算的距离,把上下移动与左右移动的距离分开算即可,用乘法原理统计路线。
代码
#include <cstdio>
int n, m, cnt;
long long ans;
char a[1001][1001];
int X[1001], Y[1001], kx[1001], ky[1001];
int main() {
scanf("%d %d", &n, &m);
cnt = n * m;
for (int i = 1; i <= n; i++)
scanf("%s", a[i] + 1);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (a[i][j] == 'X')
cnt--, kx[i] = j, ky[j] = i;
else
X[i]++, Y[j]++;
for (int i = 1; i <= m; i++) {
if (!ky[i])
continue;
int res = 0;//我是傻逼
if (ky[i + 1] > ky[i]) {
res = n - ky[i];
for (int j = i + 1; j <= m; j++)
if (ky[j] > ky[j - 1])
res += n - ky[j];
else
break;
ans += (ky[i] - 1) * res * 4;
} else if (ky[i + 1] < ky[i] && ky[i + 1]) {
res = ky[i] - 1;
for (int j = i + 1; j <= m; j++)
if (ky[j] < ky[j - 1] && ky[j])
res += ky[j] - 1;
else
break;//?
ans += (n - ky[i]) * res * 4;
} else {
ans += (ky[i] - 1) * (n - ky[i]) * 4;
}
}
for (int i = 1; i <= n; i++) {
if (!kx[i])
continue;
int res = 0;//我是傻逼
if (kx[i + 1] > kx[i]) {
res = m - kx[i];
for (int j = i + 1; j <= n; j++)
if (kx[j] > kx[j - 1])
res += m - kx[j];
else
break;
ans += (kx[i] - 1) * res * 4;
} else if (kx[i + 1] < kx[i] && kx[i + 1]) {
res = kx[i] - 1;
for (int j = i + 1; j <= n; j++)
if (kx[j] < kx[j - 1] && kx[j])
res += kx[j] - 1;
else
break;
ans += (m - kx[i]) * res * 4;
} else {
ans += (kx[i] - 1) * (m - kx[i]) * 4;
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j < i; j++)
ans += (i - j) * X[i] * X[j] * 2;
for (int i = 1; i <= m; i++)
for (int j = 1; j < i; j++)
ans += (i - j) * Y[i] * Y[j] * 2;
printf("%.4lf", (double)ans / cnt / cnt);
}
//kx,ky!=0
//j~j+1~j+2~j+3
坑
连续的一段枚举错误
没有考虑到某行或某列不存在障碍的情况