【YBTOJ】【Luogu P6474】[NOI Online #2 入门组] 荆轲刺秦王
链接:
题目大意:
从起点 \(S\) 到终点 \(T\),一个单位时间可以向八个方向走一步或上下左右四个方向走 \(d\) 步并消耗一个瞬移次数,卫兵格子走不了,特殊格子要消耗一个隐形次数才能走。求最优的情况。
正文:
本题难就难在,怎么快速地搞定这个特殊格子。我们只要用差分就好了。
然后便是用 BFS 做迷宫问题。
代码:
int n, m, c1, c2, d, tx, ty;
int dx[9] = {0, 1, -1, 0, 0, 1, -1, 1, -1},
dy[9] = {0, 0, 0, 1, -1, 1, -1, -1, 1};
struct node
{
int x, y, c1, c2, stp;
}ans;
queue <node> que;
int vis[N][N]; // >=0 - enemy, -2 - visited, -3 - invisibility, -1 - free
bool visi[N][N][20][20];
bool bfs ()
{
while (!que.empty())
{
node b = que.front(); que.pop();
if (b.stp > ans.stp) continue;
if (b.x == tx && b.y == ty)
{
if (ans.stp != b.stp) ans = ans.stp < b.stp? ans: b;
else
{
if (ans.c1 + ans.c2 != b.c1 + b.c2)
ans = ans.c1 + ans.c2 < b.c1 + b.c2? ans: b;
else
ans = ans.c1 < b.c1? ans: b;
}
continue;
}
for (int i = 1; i <= 8; i++)
{
int x = b.x + dx[i], y = b.y + dy[i];
if (vis[x][y] >= 0) continue;
if (vis[x][y] == -3)
{
if (x < 0 || x > n || y < 0 || y > m) continue;
if (b.c1 + 1 > c1 || visi[x][y][b.c1 + 1][b.c2]) continue;
visi[x][y][b.c1 + 1][b.c2] = 1;
que.push((node){x, y, b.c1 + 1, b.c2, b.stp + 1});
}
else
if(!visi[x][y][b.c1][b.c2]) que.push((node){x, y, b.c1, b.c2, b.stp + 1}),
visi[x][y][b.c1][b.c2] = 1;
}
if (b.c2 + 1 > c2) continue;
for (int i = 1; i <= 4; i++)
{
int x = b.x + dx[i] * d, y = b.y + dy[i] * d;
if (x < 0 || x > n || y < 0 || y > m) continue;
if (vis[x][y] >= 0) continue;
if (vis[x][y] == -3)
{
if (b.c1 + 1 > c1 || visi[x][y][b.c1 + 1][b.c2 + 1]) continue;
visi[x][y][b.c1 + 1][b.c2 + 1] = 1;
que.push((node){x, y, b.c1 + 1, b.c2 + 1, b.stp + 1});
}
else
if(!visi[x][y][b.c1][b.c2 + 1]) que.push((node){x, y, b.c1, b.c2 + 1, b.stp + 1}),
visi[x][y][b.c1][b.c2 + 1] = 1;
}
}
}
int tag[N][N];
void Tag(int x, int y, int k)
{
for (int i = 0; i <= k; i++)
{
tag[max(x - i, 1)][max(y - k + i, 1)]++;
tag[max(x - i, 1)][min(y + k - i, m) + 1]--;
tag[max(x + i, 1)][max(y - k + i, 1)]++;
tag[max(x + i, 1)][min(y + k - i, m) + 1]--;
}
}
int main()
{
// freopen("bandit18.in", "r", stdin);
ans = (node){0, 0, 1e9, 1e9, 1e9};
scanf ("%d%d%d%d%d", &n, &m, &c1, &c2, &d);
memset (vis, 0, sizeof vis);
for (int i = 1; i <= n; i++)
{
char c;
for (int j = 1; j <= m; j++)
{
c = getchar();
while (c != 'S' && c != 'T' && c != '.' && !(c >= '0' && c <= '9')) c = getchar();
int x = 0;
if (c == 'S') {que.push((node){i, j, 0, 0, 0});visi[i][j][0][0] = 1;continue;}
if (c == '.') {vis[i][j] = -1;continue;}
if (c == 'T') {tx = i, ty = j, vis[i][j] = -1;continue;}
while (c >= '0' && c <= '9')
x = x * 10 + c - '0', c = getchar();
vis[i][j] = x;
Tag(i, j, x - 1);
}
}
for (int i = 1; i <= n; i++)
{
int sum = 0;
for (int j = 1; j <= m; j++)
{
sum += tag[i][j];
if (sum && vis[i][j] < 1) vis[i][j] = -3;
}
}
bfs();
if(ans.stp == 1e9) puts("-1");
else printf("%d %d %d\n", ans.stp, ans.c1, ans.c2);
return 0;
}