HDU 5725 Game

 

Game

 

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

 

 

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)

题意:

n*m的图上有一些守卫,守卫的位置,满足彼此不同行,不同列,且相邻8格内不会有其他守卫,现等概率的选取起点和终点,所有可以不碰守卫可以到达的路径中,最短路径的期望。

 

解题思路:

看了题解才想到怎么写的,首先只要起点和终点不包含守卫的两点都是可达的,而每条路径最多只会背一个守卫阻挡(根据守卫的摆放规则),那么可以先把所有的合法最短路径按曼哈顿距离(即不被阻断的最短距离)计算,然后对于每守卫计算其因阻挡而额外绕行的路线长度(绕行2的距离),最后除以总路线的数目就可以了。

要注意的几点:

(1)n*m的图中任意两点的曼哈顿距离和为n*m*(n*m-1)*(n+m)/3。

(2)读图的时候最好用gets()读会快一些。

(3)要绕行如下:

绕行路线

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<map>
#include<string>
#include<queue>
#include<vector>
#include<list>
//#pragma comment(linker,"/STACK:1024000000,1024000000")
using namespace std;
#define INF 0x3f3f3f3f
int n,m;
long long dp[1005][1005];
long long dp2[505][505];
char mp[1005][1005];
//n*m的图,计算以(1,1)为起点到所有曼哈顿距离和
long long get(long long n,long long m)
{
    return m*(m-1)*n/2+n*(n-1)*m/2;
}
//n*m的图,计算任意点到所有点的曼哈顿距离和
long long get2(long long x,long long y)
{
    return get(x,y)+get(n-x+1,y)+get(x,m-y+1)+get(n-x+1,m-y+1)-(get(1,x)+get(1,y)+get(1,n-x+1)+get(1,m-y+1));
}
int xx[1005],yy[1005],cnt2;
int pr[1005],pc[1005];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        cnt2=0;
        scanf("%d%d",&n,&m);
        long long up=(long long)m*n*(m*n-1)*(m+n)/3,down=0;
        int cnt=0;
        memset(pr,-1,sizeof pr);
        memset(pc,-1,sizeof pc);
        getchar();
        for(int i=0;i<n;i++)
        {

            gets(mp[i]);
            for(int j=0;j<m;j++)
            {
                if(mp[i][j]=='G')
                {
                    pr[i]=j;
                    pc[j]=i;
                    up-=4ll*j*(m-j-1);//同行被阻断会在后面重复计算
                    up-=4ll*i*(n-i-1);//同列类似
                    up-=2*get2(i+1,j+1),cnt++;
                    xx[cnt2]=i;
                    yy[cnt2]=j;
                    cnt2++;
                }
            }
        }
        //计算绕行路径和
        int suml=0,sumr=0;
        for(int i=0;i<n;i++)
        {
            if(pr[i]!=-1)
            {
                if(i==0||pr[i]>pr[i-1]) suml+=pr[i];
                else suml=pr[i];
                up+=4ll*suml*(m-pr[i]-1);
            }
            else suml=0;
            if(pr[i]!=-1)
            {
                if(i==0||pr[i]<pr[i-1]) sumr+=m-pr[i]-1;
                else sumr=m-pr[i]-1;
                up+=4ll*sumr*pr[i];
            }
            else sumr=0;
        }
        int sumu=0,sumd=0;
        for(int i=0;i<m;i++)
        {
            if(pc[i]!=-1)
            {
                if(i==0||pc[i]>pc[i-1]) sumu+=pc[i];
                else sumu=pc[i];
                up+=4ll*sumu*(n-pc[i]-1);
            }
            else sumu=0;
            if(
               pc[i]!=-1)
            {
                if(i==0||pc[i]<pc[i-1]) sumd+=n-pc[i]-1;
                else sumd=n-pc[i]-1;
                up+=4ll*sumd*pc[i];
            }
            else sumd=0;
        }

        for(int i=0;i<cnt2;i++)
        {
            for(int j=0;j<cnt2;j++)
            {
                up+=abs(xx[i]-xx[j])+abs(yy[i]-yy[j]);
            }
        }
        down=(long long)(n*m-cnt)*(n*m-cnt);
        double ans=(long double)up/down;
        printf("%.4llf\n",ans);
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值