荆轲刺秦王【BFS】【差分】

>Link

ybtoj荆轲刺秦王


>解题思路

又是一道BFS大模拟

对荆轲的位置进行bfs,对于隐身、瞬移判断处理就可以了
因为技能使用有限制,所以我们需要在bfs的过程中记录下技能还可以用几次,对于判断一个位置是否走过同时也要加上状态(技能剩余数),及当前位置并且为当前状态的这种情况是否走过,因为状态不同也会影响从这个点到达其他位置的距离,使得可以找到更优解

这里有一个重要的地方就是预处理士兵侦查的范围(注意士兵在的位置和侦查范围是有区别的,荆轲任何时候都不可以去到士兵所在的坐标),暴力处理就会TLE
根据题目规定的 一点到士兵的曼哈顿距离小于当前士兵的能力,这个士兵就可以侦查到这个点
我们可以画出士兵侦查的范围,发现所有的范围都是一个竖着的实心的菱形,长度高度都为 2 ∗ a − 1 2*a-1 2a1,考虑到把所有士兵可以侦查到的点都累加1,那么最后大于0的点就会被侦查到
这样就变成了十分熟悉的修改区间,用 差分+前缀和 处理


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 500
#define inf 1 << 30
using namespace std;

const int xx[8] = {
    
    -1, 0, 0, 1, -1, -1, 1, 1};
const int yy[8] = {
    
    0, -1, 1, 0, -1, 1, -1, 1};
struct node
{
    
    
	int x, y, p1, p2;
};
struct node2
{
    
    
	int w, p1, p2;
} c[N][N];
int n, m, c1, c2, d, a[N][N], sx, sy, tx, ty, cnt, g[N][N];
bool mark[N][N], vis[N][N][30][30];
char cc;
queue<node> q;

void work (int x, int y, int L)
{
    
    
	int p = -1, l, r;
	for (int i = x - (2 * L - 1) / 2; i <= x + (2 * L - 1) / 2; i++)
	{
    
    
		if (i <= x) p += 2; else p -= 2;
		l = max (1, y - p / 2), r = min (m, y + p / 2);
		if (i < 1 || i > n) continue;
		g[i][l]++, g[i][r + 1]--;
	}
} //处理侦查范围
bool compare (node2 aa, node2 bb)
{
    
    
	if (aa.w != bb.w) return aa.w > bb.w;
	int ap = aa.p1 + aa.p2, bp = bb.p1 + bb.p2;
	if (ap != bp) return ap < bp;
	return aa.p1 < bb.p1;
} //按照题意比较哪个更优

int main()
{
    
    
	scanf ("%d%d%d%d%d", &n, &m, &c1, &c2, &d);
	for (int i = 1; i <= n; i++)
	  for (int j = 1; j <= m; j++) c[i][j].w = inf;
	for (int i = 1; i <= n; i++)
	  for (int j = 1; j <= m; j++)
	  {
    
    
	  	int l = 0;
	  	cc = getchar();
	  	while (cc != '.' && cc != 'S' && cc != 'T'
		       && !(cc >= '0' && cc <= '9')) cc = getchar();
	  	while (cc >= '0' && cc <= '9') {
    
    l = l * 10 + cc - '0'; cc = getchar();}
		if (l != 0) {
    
    a[i][j] = l; work (i, j, l);}
		else if (cc == 'S') sx = i, sy = j;
		else if (cc == 'T') tx = i, ty = j;
	  }
	for (int i = 1; i <= n; i++)
	  for (int j = 1; j <= m; j++)
	  {
    
    
	  	g[i][j] += g[i][j - 1];
	  	if (g[i][j] != 0) mark[i][j] = 1;
	  }
	q.push((node){
    
    sx, sy, c1, c2});
	c[sx][sy] = (node2){
    
    0, c1, c2}, vis[sx][sy][c1][c2] = 1;
	while (!q.empty())
	{
    
    
		node u = q.front(), v;
		q.pop();
		for (int i = 0; i < 8; i++)
		{
    
    
			v.x = u.x + xx[i], v.y = u.y + yy[i];
			if (v.x < 1 || v.x > n || v.y < 1 || v.y > m) continue;
			if (a[v.x][v.y] != 0) continue;
			node2 vv = (node2){
    
    c[u.x][u.y].w + 1, u.p1, u.p2};
			if (mark[v.x][v.y]) vv.p1--;
			if (vv.p1 < 0 || vv.p2 < 0) continue;
			if (compare (c[v.x][v.y], vv))
			{
    
    
				c[v.x][v.y] = vv;
				v.p1 = vv.p1, v.p2 = vv.p2;
				if (!vis[v.x][v.y][v.p1][v.p2])
				{
    
    
					vis[v.x][v.y][v.p1][v.p2] = 1;
					q.push (v);
				}
			}
		} //正常走
		if (u.p2 > 0) //瞬移
		  for (int i = 0; i < 4; i++)
		  {
    
    
			v.x = u.x + d * xx[i], v.y = u.y + d * yy[i];
			if (v.x < 1 || v.x > n || v.y < 1 || v.y > m) continue;
			if (a[v.x][v.y] != 0) continue;
			node2 vv = (node2){
    
    c[u.x][u.y].w + 1, u.p1, u.p2 - 1};
			if (mark[v.x][v.y]) vv.p1--;
			if (vv.p1 < 0 || vv.p2 < 0) continue;
			if (compare (c[v.x][v.y], vv))
			{
    
    
				c[v.x][v.y] = vv;
				v.p1 = vv.p1, v.p2 = vv.p2;
				if (!vis[v.x][v.y][v.p1][v.p2])
				{
    
    
					vis[v.x][v.y][v.p1][v.p2] = 1;
					q.push (v);
				}
			}
		  }
		vis[u.x][u.y][u.p1][u.p2] = 0;
	}
	if (c[tx][ty].w == inf) printf ("-1");
	else
	  printf ("%d %d %d", c[tx][ty].w, c1 - c[tx][ty].p1, c2 - c[tx][ty].p2);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/113003543