[补题记录] Atcoder Beginner Contest 317(E)

URL:https://atcoder.jp/contests/abc317

目录

E

Problem/题意

Thought/思路

Code/代码


E

Problem/题意

有四种箭头 ^、>、<、v 和一种障碍 #,箭头所指向的方向回生成一路障碍直到遇到另一个障碍或者箭头。

问 S 到 G 的最短路径。

Thought/思路

显然难点在于如何生成箭头的障碍。

我们可以为每一列和每一行都记录上在某行或者某列的所有箭头或障碍,随后遍历所有箭头和障碍,根据箭头方向在某行或者某列上,二分查找下一个或上一个箭头或障碍

找到区间后维护一个二维前缀和。

最后求最短路径。

(写完才发现写了好长的代码,其他人更简短的:https://blog.csdn.net/weixin_66946161/article/details/132516511)

Code/代码

#include "bits/stdc++.h"

int h, w, pre[2003][2003], dis[2003][2003], vis[2003][2003];
char mp[2003][2003];

const int inf = 1e9 + 7;
const int dx[] = { -1, 0, 1, 0, -1 };

std::vector  vx[2003], vy[2003];

struct node {
	int x, y;
};
std::vector  v;

node S, G;

int getX(char dir, int x, int y) {
	int l = -1, r = vy[y].size();
	if (dir == '^') {
		while (l + 1 != r) {
			int mid = (l + r) / 2;
			if (vy[y][mid] < x) l = mid;
			else r = mid;
		}
		return vy[y][l];
	} else if (dir == 'v') {
		while (l + 1 != r) {
			int mid = (l + r) / 2;
			if (x < vy[y][mid]) r = mid;
			else l = mid;
		}
		return vy[y][r];
	}
}

int getY(char dir, int x, int y) {
	int l = -1, r = vx[x].size();
	if (dir == '<') {
		while (l + 1 != r) {
			int mid = (l + r) / 2;
			if (vx[x][mid] < y) l = mid;
			else r = mid;
		}
		return vx[x][l];
	} else if (dir == '>') {
		while (l + 1 != r) {
			int mid = (l + r) / 2;
			if (y < vx[x][mid]) r = mid;
			else l = mid;
		}
		return vx[x][r];
	}
}

bool check(int x, int y) {
	if (pre[x][y] > 0 or x < 1 or x > h or y < 1 or y > w or mp[x][y] == '#') return false;
	else return true; 
}

void bfs(int sx, int sy) {
	for (int i = 0; i <= h + 1; ++ i) {
		for (int j = 0; j <= w + 1; ++ j) {
			dis[i][j] = inf;
		}
	}

	std::queue  q;
	q.push({sx, sy});
	dis[sx][sy] = 0;

	while (!q.empty()) {
		auto o = q.front(); q.pop();

		int x = o.x, y = o.y;
		for (int i = 0; i <= 3; ++ i) {
			int nx = x + dx[i], ny = y + dx[i + 1];
			if (check(nx, ny)) {
				if (dis[nx][ny] > dis[x][y] + 1) {
					dis[nx][ny] = dis[x][y] + 1;
					q.push({nx, ny});
				}
			}
		}
	}
}

signed main() {
	std::cin >> h >> w;

	for (int x = 0; x <= h + 1; ++ x) vx[x].push_back(0);
	for (int y = 0; y <= w + 1; ++ y) vy[y].push_back(0);

	for (int i = 1; i <= h; ++ i) {
		for (int j = 1; j <= w; ++ j) {
			std::cin >> mp[i][j];
			char c = mp[i][j];
			if (c == '^' or c == 'v' or c == '<' or c == '>' or c == '#'){
				vx[i].push_back(j);
				vy[j].push_back(i);
				v.push_back({i, j});
			} else if (c == 'S') {
				S = {i, j};
			} else if (c == 'G') {
				G = {i, j};
			}
		}
	}

	for (int x = 0; x <= h + 1; ++ x) vx[x].push_back(w + 1);
	for (int y = 0; y <= w + 1; ++ y) vy[y].push_back(h + 1);

	for (auto &pair : v) {
		int x = pair.x, y = pair.y;
		int xl = 0, xr = 0, yl = 0, yr = 0;
		if (mp[x][y] == '#') continue;
		else if (mp[x][y] == '^' or mp[x][y] == 'v') {
			if (mp[x][y] == '^')
				xl = getX('^', x, y), xr = x;
			if (mp[x][y] == 'v')
				xr = getX('v', x, y), xl = x;
			xl = (xl == 0 ? 1 : xl);
			xr = (xr == 0 ? 1 : xr);
			pre[xl][y] ++;
			pre[xl][y + 1] --;
			pre[xr + 1][y] --;
			pre[xr + 1][y + 1] ++;
			//std::cout << xl << " " << y << " -- " << xr << " " << y << "\n";
		} else if (mp[x][y] == '<' or mp[x][y] == '>') {
			if (mp[x][y] == '<')
				yl = getY('<', x, y), yr = y;
			if (mp[x][y] == '>')
				yr = getY('>', x, y), yl = y;
			yl = (yl == 0 ? 1 : yl);
			yr = (yr == 0 ? 1 : yr); 
			pre[x][yl] ++;
			pre[x + 1][yl] --;
			pre[x][yr + 1] --;
			pre[x + 1][yr + 1] ++;
			//std::cout << x << " " << yl << " -- " << x << " " << yr << "\n";
		}
	}
	for (int i = 1; i <= h; ++ i) {
		for (int j = 1; j <= w; ++ j) {
			pre[i][j] += pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1];
		}
	}

	bfs(S.x, S.y);

	std::cout << (dis[G.x][G.y] == inf ? -1 : dis[G.x][G.y]);
}

你可能感兴趣的:(补题记录,算法,图论)