>Link
ybtoj荆轲刺秦王
>解题思路
又是一道BFS大模拟
对荆轲的位置进行bfs,对于隐身、瞬移判断处理就可以了
因为技能使用有限制,所以我们需要在bfs的过程中记录下技能还可以用几次,对于判断一个位置是否走过同时也要加上状态(技能剩余数),及当前位置并且为当前状态的这种情况是否走过,因为状态不同也会影响从这个点到达其他位置的距离,使得可以找到更优解
这里有一个重要的地方就是预处理士兵侦查的范围(注意士兵在的位置和侦查范围是有区别的,荆轲任何时候都不可以去到士兵所在的坐标),暴力处理就会TLE
根据题目规定的 一点到士兵的曼哈顿距离小于当前士兵的能力,这个士兵就可以侦查到这个点
我们可以画出士兵侦查的范围,发现所有的范围都是一个竖着的实心的菱形,长度高度都为 2 ∗ a − 1 2*a-1 2∗a−1,考虑到把所有士兵可以侦查到的点都累加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;
}