어흥

[백준 1944] 복제 로봇 (C++) 본문

알고리즘/백준

[백준 1944] 복제 로봇 (C++)

라이언납시오 2020. 4. 15. 21:45
728x90
반응형

문제 링크: https://www.acmicpc.net/problem/1944

 

1944번: 복제 로봇

첫째 줄에 미로의 크기 N(4 ≤ N ≤ 50)과 열쇠의 개수 M(1 ≤ M ≤ 250) 이 공백을 사이에 두고 주어진다. 그리고 둘째 줄부터 N+1째 줄까지 미로의 정보가 주어진다. 미로는 1과 0, 그리고 S와 K로 주어진다. 1은 미로의 벽을 의미하고, 0은 지나다닐 수 있는 길, S는 로봇이 출발하는 위치, K는 열쇠의 위치가 주어진다. S는 1개, K는 M개가 주어진다. S와 K에서만 복제를 할 수 있음에 유의한다.

www.acmicpc.net

1. 주의할 점

- MST 알고리즘에 대해 알고 있어야 한다.

- 시작점을 따로 기억하고 S 또한 K와 같은 Node로 취급한다

- S 와 K 모두 Node로 취급하므로 최대 251개의 Node가 있다 -> 고려 안하면 Runtime Error 발생

 

2. 구현

- S와 K를 Node로 취급하여 Node 벡터에 모두 기록한다

- S가 몇 번째 Node인지 따로 기억한다

- 각 Node에서 다른 Node까지의 최소 거리를 BFS를 통하여 구한다

- S가 로봇의 시작점이므로 S Node를 기준으로 Prim알고리즘을 적용하여 MST를 구한다

- Prim알고리즘이 끝난 후, 모든 Node를 방문했는지 확인하여 방문했다면 MST의 결과를 출력하고, 모든 Node를 방문하지 못했다면 -1을 출력한다.

 

Prim 알고리즘이란?

1. 시작 Node를 Queue에 넣는다(결과적으로, Queue에는 항상 0개 or 1개의 Node만 존재한다)

2. While(q.empty())를 통해 queue에서 1개씩 Node번호를 빼면서 해당 Node에 이어진 모든 간선중, 간선을 기준으로 반대편에 위치한 Node가 방문하지 않은 Node일때 우선순위 큐에 넣는다

3. 간선의 가중치가 오름차순으로 정렬되도록 정렬된 우선순위큐에서 While(pq.empty())를 통해 우선순위큐에서 1개씩 추출하면서 다음 Node가 방문하지 않은 Node라면 해당 Node를 Queue에 넣고 While(pq.empty())문을 종료하고 2번으로 돌아간다

 

#define MAX 987654321
#include <iostream>
#include <queue>
#include <vector>
#include <string>
using namespace std;
int arr[50][50];	//벽: -1, 시작위치와 키 위치>=1
int check[50][50];
bool visit[252] = { false, };
int num, key;
int dx[4] = { 0,1,0,-1 };
int dy[4] = { -1,0,1,0 };

struct info {
	int idx, val;
};
struct cmp {
	bool operator()(info &a, info &b) {
		return a.val > b.val;
	}
};
struct info2 {
	int x, y;
};
info tmp;
info2 tmp2;
vector<info> v[252];
vector<info2> node;		//각 Node에 대한 정보를 담고 있다

int main() {
	ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
	cin >> num >> key;
	int cnt = 1, sidx;
	char c;
	string str;
	for (int i = 0; i < num; i++) {
		cin >> str;
		for (int j = 0; j < num; j++) {
			c = str[j];
			if (c == '1') arr[i][j] = -1;
			else if (c == '0') arr[i][j] = 0;
			else {
				if (c == 'S') sidx = cnt;
				arr[i][j] = cnt++;
				tmp2.x = j;
				tmp2.y = i;
				node.push_back(tmp2);
			}
		}
	}
	//prim 알고리즘을 사용하기 위해 각 Node에서 서로 다른 Node까지의 거리를 구한다
	for (int t = 1; t <= key + 1; t++) {
		for (int i = 0; i < num; i++)
			for (int j = 0; j < num; j++)
				check[i][j] = MAX;
		queue<info2> q;
		tmp2.x = node[t - 1].x;
		tmp2.y = node[t - 1].y;
		q.push(tmp2);
		check[tmp2.y][tmp2.x] = 0;
		while (!q.empty()) {
			int cx = q.front().x;
			int cy = q.front().y;
			int cv = check[cy][cx];
			q.pop();
			for (int i = 0; i < 4; i++) {
				int nx = cx + dx[i];
				int ny = cy + dy[i];
				if (nx >= 0 && ny >= 0 && nx < num && ny < num && arr[ny][nx]!=-1) {
					if (check[ny][nx] == MAX) {
						check[ny][nx] = cv + 1;
						if (arr[ny][nx] != 0) {		//다른 node인 경우
							tmp.idx = arr[ny][nx];
							tmp.val = cv + 1;
							v[t].push_back(tmp);
							continue;
						}
						//node도 벽도 아닌 경우
						tmp2.x = nx;
						tmp2.y = ny;					
						q.push(tmp2);
					}
				}
			}
		}
	}
	//prim 알고리즘
	priority_queue<info, vector<info>, cmp> pq;
	queue<int> q;
	int result = 0;
	q.push(sidx);
	while (!q.empty()) {
		int cidx = q.front();
		q.pop();
		visit[cidx] = true;
		for (int i = 0; i < v[cidx].size(); i++) {
			int next = v[cidx][i].idx;
			int nv = v[cidx][i].val;
			if (!visit[next]) {
				tmp.idx = next;
				tmp.val = nv;
				pq.push(tmp);
			}
		}
		while (!pq.empty()) {
			int next = pq.top().idx;
			int nv = pq.top().val;
			pq.pop();
			if (visit[next]) continue;
			result += nv;
			q.push(next);
			break;
		}
	}
	//모두 방문이 불가능한 경우 처리
	for (int i = 1; i <= key + 1; i++) {
		if (!visit[i]) {
			result = -1;
			break;
		}
	}
	cout << result;
	system("pause");
	return 0;
}
728x90
반응형

'알고리즘 > 백준' 카테고리의 다른 글

[백준 16973] 직사각형 탈출 (C++)  (0) 2020.04.17
[백준 7682] 틱택토 (C++)  (2) 2020.04.16
[백준 1504] 특정한 최단 경로 (C++)  (0) 2020.04.14
[백준 1701] Cubeditor (C++)  (0) 2020.04.12
[백준 1786] 찾기 (JAVA)  (0) 2020.04.10
Comments