2016 Multi-University Training Contest 1 C.Game

时间:2021-11-20 08:37:10

Game

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 588    Accepted Submission(s): 146

Problem Description
  Sea5 and wzh are playing games.

There are some guards on an n × m chessboard. Every guard can attack eight cells around him and release shockwave to attack the whole row and column where he stand.

Sea5 and wzh are at the beginning stage of the game, they have already put some guards on the chess cells. No guards can be attacked by another guard right now. So they all fell asleep.

An innocent passer-by is on the chessboard. He can move to up, down, left or right from where he stands. The guards won’t attack him unless the passer-by move to where they stand. The innocent man may appear at any point on the chessboard and move to any point.

The innocent passer-by wants to know the average shortest distance of all the ways he can move without attacked by guards.

 
Input
  Multiple test cases.

The first line is an integer T(T≤50), the number of cases.

For each case, first line is two integers n and m(2≤n,m,≤1000).

The next n lines contain m symbols indicate the cells of chessboard. ‘G’ indicates a guard and ‘#’ indicates an empty cell.

 
Output
  One line per case, shortest distance of all the ways the passer-by can move without attacked by guards.

Round the answer to four decimals.

 
Sample Input
1
2 2
##
G#
 
Sample Output
0.8889
Hint

Ways of distance 0: 3
Ways of distance 1: 4
Ways of distance 2: 2
The answer is (3 * 0 + 1 * 4 + 2 * 2) / (3 + 4 + 2)

 
Author
HIT
 
Source
 
题意:问一个图中,在不经过障碍的前提下,随意选取起点终点的期望路径长度。
有一个条件,就是障碍物每行、每列只有一个,且一个障碍的八联通方格内不会有另一个障碍。

  

题解:
障碍物的条件使此题简单不少。
1、首先两个格子要么不会被阻碍(即最小距离为曼哈顿距离),要么只会绕行2的距离。
证明:
按照此种策略走即可:假设起点在左上方,终点在右下方,不影响结论。
那么,先优先往下走,若被阻挡则往右移动一个单位,再重复这个过程。
可以知道最后要么直接到达终点,要么停留在与终点同一条直线上(正上方或者正左方)。后者只需绕行距离2。 2、被阻挡的情形为 #S###
#####
#G###
#####
##G##
#####
###G#
###E# 即从S到E每一个竖列都有障碍。
其余情况可以有这种情况翻转得到。

  

 const int N = ;
int n, m;
char graph[N][N];
int onx[N], ony[N];
// onx -> The y coordinate of the guard on i x-coordinate
// ony -> The x coordinate of the guard on i y-coordinate inline ll manhattanTo(int x, int y) {
++x, ++y;
ll deltax = ( * x * x - * x + n * n - * n * x + n);
ll deltay = ( * y * y - * y + m * m - * m * y + m);
return deltax * m / + deltay * n / ;
} inline void init() {
clr(onx, -), clr(ony, -);
for(int i = ; i < n; ++i)
for(int j = ; j < m; ++j)
if(graph[i][j] == 'G') onx[i] = j, ony[j] = i;
} inline void upsidedown() {
for(int i = , _i = n - i - ; i < _i; ++i, --_i)
for(int j = ; j < m; ++j) swap(graph[i][j], graph[_i][j]);
init();
} inline void symmetryflip() {
int len = max(n, m);
for(int i = ; i < len; ++i)
for(int j = i; j < len; ++j) swap(graph[i][j], graph[j][i]);
swap(n, m);
init();
} inline ll work() {
// only work for these kind
// #G......
// ...G....
// ......G#
ll ret = ;
int lasty = -, cnt = ;
for(int i = ; i < n; ++i)
if(onx[i] == -) lasty = -, cnt = ;
else if(onx[i] > lasty) {
ret += cnt * 2ll * (m - onx[i] - );
lasty = onx[i], cnt += onx[i];
} else lasty = onx[i], cnt = onx[i];
return ret;
} inline void solve() {
init(); ll nm = n * m;
ll ans = (nm - ) * nm * (n + m) / ;
// cout << ans << endl; // The start point is guard
for(int i = ; i < n; ++i)
for(int j = ; j < m; ++j)
if(graph[i][j] == 'G') ans -= manhattanTo(i, j);
// The end point is guard
for(int i = ; i < n; ++i)
for(int j = ; j < m; ++j)
if(graph[i][j] == 'G') ans -= manhattanTo(i, j);
// Both start point and end point are guard
for(int i = ; i < n; ++i)
if(onx[i] != -) {
for(int j = ; j < n; ++j)
if(onx[j] != -) ans += abs(onx[i] - onx[j]);
}
for(int i = ; i < m; ++i)
if(ony[i] != -) {
for(int j = ; j < m; ++j)
if(ony[j] != -) ans += abs(ony[i] - ony[j]);
}
// cout << ans << endl; // Detour in one line
for(int i = ; i < n; ++i)
if(onx[i] != -) ans += 4ll * onx[i] * (m - onx[i] - );
for(int i = ; i < m; ++i)
if(ony[i] != -) ans += 4ll * ony[i] * (n - ony[i] - );
// Detour for block
// #..
// G..
// ...
// .G.
// ...
// ..G
// ..#
ans += 2ll * work();
upsidedown();
ans += 2ll * work();
symmetryflip();
ans += 2ll * work();
upsidedown();
ans += 2ll * work(); int noGuards = n * m;
for(int i = ; i < n; ++i)
for(int j = ; j < m; ++j)
if(graph[i][j] == 'G') --noGuards;
ll ways = noGuards * 1ll * noGuards; // cout << noGuards << endl;
// cout << ans << " " << ways << endl; printf("%.4lf\n", ans / (. * ways));
} int main() {
int testCase;
scanf("%d", &testCase);
while(testCase--) {
scanf("%d%d", &n, &m);
for(int i = ; i < n; ++i) scanf("%s", graph[i]);
solve();
}
return ;
}