【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;
}
posted @ 2021-01-22 14:17  Jayun  阅读(78)  评论(0编辑  收藏  举报