2016 Multi-University Training Contest 1 C.Game

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(T50), the number of cases.

  For each case, first line is two integers n and m(2n,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每一个竖列都有障碍。
其余情况可以有这种情况翻转得到。

  

 

  1 const int N = 1010;
  2 int n, m;
  3 char graph[N][N];
  4 int onx[N], ony[N];
  5 // onx -> The y coordinate of the guard on i x-coordinate
  6 // ony -> The x coordinate of the guard on i y-coordinate
  7 
  8 inline ll manhattanTo(int x, int y) {
  9     ++x, ++y;
 10     ll deltax = (2 * x * x - 2 * x + n * n - 2 * n * x + n);
 11     ll deltay = (2 * y * y - 2 * y + m * m - 2 * m * y + m);
 12     return deltax * m / 2 + deltay * n / 2;
 13 }
 14 
 15 inline void init() {
 16     clr(onx, -1), clr(ony, -1);
 17     for(int i = 0; i < n; ++i)
 18         for(int j = 0; j < m; ++j)
 19             if(graph[i][j] == 'G') onx[i] = j, ony[j] = i;
 20 }
 21 
 22 inline void upsidedown() {
 23     for(int i = 0, _i = n - i - 1; i < _i; ++i, --_i)
 24         for(int j = 0; j < m; ++j) swap(graph[i][j], graph[_i][j]);
 25     init();
 26 }
 27 
 28 inline void symmetryflip() {
 29     int len = max(n, m);
 30     for(int i = 0; i < len; ++i)
 31         for(int j = i; j < len; ++j) swap(graph[i][j], graph[j][i]);
 32     swap(n, m);
 33     init();
 34 }
 35 
 36 inline ll work() {
 37     // only work for these kind
 38     // #G......
 39     // ...G....
 40     // ......G#
 41     ll ret = 0;
 42     int lasty = -1, cnt = 0;
 43     for(int i = 0; i < n; ++i)
 44         if(onx[i] == -1) lasty = -1, cnt = 0;
 45         else if(onx[i] > lasty) {
 46             ret += cnt * 2ll * (m - onx[i] - 1);
 47             lasty = onx[i], cnt += onx[i];
 48         } else lasty = onx[i], cnt = onx[i];
 49     return ret;
 50 }
 51 
 52 inline void solve() {
 53     init();
 54 
 55     ll nm = n * m;
 56     ll ans = (nm - 1) * nm * (n + m) / 3;
 57     // cout << ans << endl;
 58 
 59     // The start point is guard
 60     for(int i = 0; i < n; ++i)
 61         for(int j = 0; j < m; ++j)
 62             if(graph[i][j] == 'G') ans -= manhattanTo(i, j);
 63     // The end point is guard
 64     for(int i = 0; i < n; ++i)
 65         for(int j = 0; j < m; ++j)
 66             if(graph[i][j] == 'G') ans -= manhattanTo(i, j);
 67     // Both start point and end point are guard
 68     for(int i = 0; i < n; ++i)
 69         if(onx[i] != -1) {
 70             for(int j = 0; j < n; ++j)
 71                 if(onx[j] != -1) ans += abs(onx[i] - onx[j]); 
 72         }
 73     for(int i = 0; i < m; ++i)
 74         if(ony[i] != -1) {
 75             for(int j = 0; j < m; ++j)
 76                 if(ony[j] != -1) ans += abs(ony[i] - ony[j]); 
 77         }
 78     // cout << ans << endl;
 79 
 80     // Detour in one line
 81     for(int i = 0; i < n; ++i)
 82         if(onx[i] != -1) ans += 4ll * onx[i] * (m - onx[i] - 1);
 83     for(int i = 0; i < m; ++i)
 84         if(ony[i] != -1) ans += 4ll * ony[i] * (n - ony[i] - 1);
 85     // Detour for block
 86     // #..
 87     // G..
 88     // ...
 89     // .G.
 90     // ...
 91     // ..G
 92     // ..#
 93     ans += 2ll * work();
 94     upsidedown();
 95     ans += 2ll * work();
 96     symmetryflip();
 97     ans += 2ll * work();
 98     upsidedown();
 99     ans += 2ll * work();
100 
101     int noGuards = n * m;
102     for(int i = 0; i < n; ++i)
103         for(int j = 0; j < m; ++j)
104             if(graph[i][j] == 'G') --noGuards;
105     ll ways = noGuards * 1ll * noGuards;
106 
107     // cout << noGuards << endl;
108     // cout << ans << " " << ways << endl;
109 
110     printf("%.4lf\n", ans / (1. * ways));
111 }
112 
113 int main() {
114     int testCase;
115     scanf("%d", &testCase);
116     while(testCase--) {
117         scanf("%d%d", &n, &m);
118         for(int i = 0; i < n; ++i) scanf("%s", graph[i]);
119         solve();
120     }
121     return 0;
122 }
View Code

 

 

 

posted @ 2016-08-24 22:08  yanzx6  阅读(192)  评论(0编辑  收藏  举报