结论+枚举

题意

给定一个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

连续的一段枚举错误
没有考虑到某行或某列不存在障碍的情况