Problem Solving/BOJ(백준)
[BOJ]백준 1944번: 복제 로봇(C++) / MST, BFS
이진2
2021. 3. 29. 00:49
1944번: 복제 로봇
첫째 줄에 미로의 크기 N(4 ≤ N ≤ 50)과 열쇠의 개수 M(1 ≤ M ≤ 250) 이 공백을 사이에 두고 주어진다. 그리고 둘째 줄부터 N+1째 줄까지 미로의 정보가 주어진다. 미로는 1과 0, 그리고 S와 K로 주어
www.acmicpc.net
스터디 문제 풀이용으로 급하게 서치한 문제인데 굉장히 유익한 것 같아서 포스팅
로봇의 시작 좌표 S가 주어지고, 열쇠의 좌표 K(여러 개)가 주어졌을 떄 모든 열쇠를 얻을 수 있는 최단거리 이동 경로를 구해야 한다.
이 때, 이동 경로에는 가중치가 없고(BFS를 이용한 최단거리 계산) 열쇠가 복사가 가능하기 때문(S에서만 K를 도달할 수 있는게 아닌, K에서 다른 K로도 이동 가능)에 MST로 풀이가 가능하다.
즉 이런 식으로 S, K들 사이에 edge를 연결(좌표 상에서의 최단거리 계산으로)해서 거리를 구하고, 그 edge들의 cost합이 최소가 되는 MST를 생성하면 된다.
나는 그림에 적은 것 처럼 모든 좌표에서 BFS를 돌려서 좌표 상에서의 최단 거리를 구해주고, 그것을 이용해서 MST를 만들었다. cost값이 하나라도 INF인 노드가 있다면 MST를 생성할 수 없다는 뜻 이므로(MST는 connected graph에서만 생성 가능) -1를 return해주었다.
#include <iostream>
#include <queue>
#include <string>
#include <algorithm>
#define INF 987654321
#define pii pair<int,int>
using namespace std;
typedef struct { int x,y; }point;
//string map[51];
int map[51][51];
int n, m,dist[255][255];
int dx[] = { 1,0,-1,0 }, dy[] = { 0,1,0,-1 };
vector<point> v;
void bfs(point p) {
bool visit[51][51] = { 0 };
queue<point> q;
q.push({ p.x,p.y });
visit[p.y][p.x] = 1;
int d = 0;
while (!q.empty()) {
int size = q.size();
for (int s = 0; s < size; s++) {
point cur = q.front(); q.pop();
if (map[cur.y][cur.x] > 0) {
dist[map[p.y][p.x]][map[cur.y][cur.x]] = d;
}
for (int i = 0; i < 4; i++) {
int nx = cur.x + dx[i], ny = cur.y + dy[i];
if (map[ny][nx] == -1 || visit[ny][nx])continue;
q.push({ nx,ny });
visit[ny][nx] = 1;
}
}
d++;
}
}
int prim() {
priority_queue<pii, vector<pii>, greater<>> pq;
vector<int> cost(m + 2, INF);
vector<int> prev(m + 2, -1);
vector<bool> visit(m + 2, false);
int ans = 0;
pq.push(make_pair(0, 1));
cost[1] = 0;
while (!pq.empty()) {
pii cur = pq.top(); pq.pop();
if (visit[cur.second])continue;
visit[cur.second] = 1;
for (int i = 1; i <= m + 1; i++) {
if (dist[cur.second][i] != INF &&
(cost[i] > dist[cur.second][i])
&&!visit[i]) {
cost[i] = dist[cur.second][i];
prev[i] = cur.second;
pq.push(make_pair(cost[i], i));
}
}
}
for (int i = 1; i <= m + 1; i++) {
if (cost[i] == INF)return -1;
ans += cost[i];
}
return ans;
}
int main() {
cin >> n >> m;
int eNum = 2;
for (int i = 0; i < n; i++) {
string s;
cin >> s;
for (int j = 0; j < n; j++) {
switch (s[j]) {
case '1':
map[i][j] = -1;
break;
case '0':
map[i][j] = 0;
break;
case 'S':
map[i][j] = 1;
v.push_back({ j,i });
break;
default:
map[i][j] = eNum++;
v.push_back({ j,i });
break;
}
}
}
fill(&dist[0][0], &dist[m + 3][m + 2], INF);
for (int i = 0; i < v.size(); i++)
bfs(v[i]);
printf("%d", prim());
return 0;
}
너무 빤한 MST 문제가 아닌 고민할 거리를 추가해줘서 good problem이라고 생각한다.