BOJ14497

주난의 난

문제출처

문제 해석

  • 주난이가 초코바를 가지고 있는 범인을 찾기 위해 최소로 점프해야 하는 수를 구하는 문제입니다.
  • 주난이가 한번 점프를 하면 파동이 장애물(친구)를 만날 때까지 퍼지게 됩니다.
  • N, M <= 300

설계(10)

  • 범위가 작으므로 dfs를 이용하여 친구들을 만날 때까지 탐색을 한 후, 만나는 친구들의 좌표를 벡터에 저장합니다.
  • 저장된 좌표들을 0으로 변환 후, 파동수를 올려서 다음 탐색을 진행하게 됩니다.
  • 시간복잡도가 O(NM*max(N,M)) 이므로 시간 안에 해결할 수 있습니다.
  • 공개코드 처리된 zagabi님의 코드를 참조해 보면 bfs를 이용해 O(NM)으로 최적화를 할 수 있습니다.

구현(10)

코드
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <vector>
#define MAXN 300
using namespace std;

char map[MAXN][MAXN];
bool visited[MAXN][MAXN];
int N, M;

vector<pair<int, int> > v;

bool flag = false;
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
void dfs(int x, int y) {
	if (flag) return;
	visited[x][y] = true;
	for (int k = 0; k < 4; k++) {
		int nx = x + dx[k];
		int ny = y + dy[k];
		if (nx < 0 || ny < 0 || nx >= N || ny >= M) continue;
		if (visited[nx][ny]) continue;
		if (map[nx][ny] == '0') {
			dfs(nx, ny);
		}
		else if (map[nx][ny] == '1') {
			v.push_back({ nx,ny });
		}
		else if (map[nx][ny] == '#') {
			flag = true;
			return;
		}
	}
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	scanf("%d%d", &N, &M);
	int x1, y1, x2, y2;
	scanf("%d%d%d%d", &x1, &y1, &x2, &y2);

	x1--;
	y1--;
	x2--;
	y2--;
	for (int i = 0; i < N; i ++ ) {
		for (int j = 0; j < M; j++) {
			scanf(" %1c", &map[i][j]);
		}
	}
	int ans = 0;

	while (!flag) {
		ans++;
		memset(visited, false, sizeof(visited));
		v.clear();
		dfs(x1, y1);
		for (int i = 0; i < v.size(); i++) {
			map[v[i].first][v[i].second] = '0';
		}
	}
	cout << ans << "\n";
	return 0;
}

코드2(최적화)
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <queue>
#define MAXN 300
using namespace std;

char map[MAXN][MAXN];
int dist[MAXN][MAXN];
int N, M;

vector<pair<int, int> > v;

bool flag = false;
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	scanf("%d%d", &N, &M);
	int x1, y1, x2, y2;
	scanf("%d%d%d%d", &x1, &y1, &x2, &y2);

	x1--;
	y1--;
	x2--;
	y2--;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			scanf(" %1c", &map[i][j]);
		}
	}
	int ans = 0;
	queue < pair<int, int> > q;
	q.push({ x1,y1 });
	dist[x1][y1] = 0;
	while (map[x2][y2] != '0') {
		ans++;
		queue<pair<int, int> > tmp_q;
		while (!q.empty()) {
			int x = q.front().first;
			int y = q.front().second;
			q.pop();
			for (int i = 0; i < 4; i++) {
				int nx = x + dx[i];
				int ny = y + dy[i];
				if (nx < 0 || ny < 0 || nx >= N || ny >= M || dist[nx][ny]) continue;
				dist[nx][ny] = ans;
				if (map[nx][ny] != '0') {
					map[nx][ny] = '0';
					tmp_q.push({ nx,ny });
				}
				else {
					q.push({ nx,ny });
				}
			}
		}
		q = tmp_q;
	}
	cout << ans << "\n";
	return 0;
}

디버깅
제출결과

4ms

마무리

  • 기본적인 탐색방법으로 범위가 작아 깊게 고민하지 않은 문제입니다.