【HDU5725 2016 Multi-University Training Contest 1C】【最短路 曼哈顿距离+贪心 前缀和】Game 有特殊守卫地图中所有空格点的最短路之和

84 篇文章 5 订阅
11 篇文章 0 订阅

Game

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


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

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 1010, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int n, m;
char a[N][N];
int line[N], list[N];
int Y[N], X[N];
int main()
{
	scanf("%d", &casenum);
	for (casei = 1; casei <= casenum; ++casei)
	{
		MS(line, 0); MS(list, 0);
		MS(Y, 0); MS(X, 0);
		scanf("%d%d", &n, &m);
		LL tot = 0;
		for (int i = 1; i <= n; ++i)
		{
			scanf("%s", a[i] + 1);
			for (int j = 1; j <= m; ++j)
			{
				if (a[i][j] == 'G')
				{
					Y[i] = j;
					X[j] = i;
				}
				else
				{
					++line[i];
					++list[j];
					++tot;
				}
			}
		}
		LL ans = 0, num, sum;
		num = sum = 0;
		for (int i = 1; i <= n; ++i)
		{
			ans += (i * num - sum)*line[i];
			num += line[i];
			sum += line[i] * i;
		}
		num = sum = 0;
		for (int i = 1; i <= m; ++i)
		{
			ans += (i * num - sum)*list[i];
			num += list[i];
			sum += list[i] * i;
		}
		ans *= 2;
		LL bef, beh;
		bef = beh = 0;
		for (int i = 1; i <= n; ++i)
		{
			if (!Y[i])bef = beh = 0;
			else
			{
				bef = (Y[i - 1] && Y[i - 1] < Y[i])*bef + (Y[i] - 1);
				beh = (Y[i - 1] > Y[i])*beh + (m - Y[i]);
				ans += bef * beh * 4;
			}
		}
		bef = beh = 0;
		for (int i = 1; i <= m; ++i)
		{
			if (!X[i])bef = beh = 0;
			else
			{
				bef = (X[i - 1] && X[i - 1] < X[i])*bef + (X[i] - 1);
				beh = (X[i - 1] > X[i])*beh + (n - X[i]);
				ans += bef * beh * 4;
			}
		}
		printf("%.4f\n", ans / (tot * tot * 1.0));
	}
	return 0;
}
/*
【trick&&吐槽】
这题是上一场多校唯一没有读的题,但似乎并不是很难?
果然不难。TwT 。多读题、敢开题,非常重要。

【题意】
给你一个n*m(1000*1000)的棋盘,有若干守卫'G',其余位置为空地'#'。
对于每个守卫,可以攻击到——
1,周围8个点
2,同行或同列的点
这些守卫之间无法相互攻击到。
问你,所有空地之间最短路的距离之和是多少(最短路不允许经过'G'点)

【类型】
最短路 脑洞

【分析】
这种乱搞题我竟然没有发现,我是大傻逼啊。
首先,我们发现我们不允许经过'G'点,而'G'点之间又有着之间相互攻击不到的关系。

思考:
地图大小太大,我们做最短路是吃不消的。
于是两点之间的最短路,应该有更快的计算方式。
猜想——两点之间的最短路,是否为这两点间的曼哈顿距离呢?
显然不一定是。
然而,我们研究这个地图,两点之间的最短路,有怎样的规律呈现呢?    

1,最多只会因为格子的阻挡走一次弯路。
2,走一次弯路的条件是——
	(1),同行同列
	(2),非同行同列,但被阶梯型阻挡。

这个阶梯型阻挡很有特点,我们可以通过前缀和更新答案。
然后问题情况就变得很简单。

于是——
对于这道题而言——
曼哈顿距离预处理+前缀和更新阻挡情况=AC

【时间复杂度&&优化】
O(nm)

【数据】
input
100
5 5
####G
G####
##G##
#####
#G###
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值