• [백준OJ] 1944번 복제 로봇

    2021. 7. 18.

    by. Hyeon-Uk

    반응형

    https://www.acmicpc.net/problem/1944

     

    1944번: 복제 로봇

    첫째 줄에 미로의 크기 N(4 ≤ N ≤ 50)과 열쇠의 개수 M(1 ≤ M ≤ 250) 이 공백을 사이에 두고 주어진다. 그리고 둘째 줄부터 N+1째 줄까지 미로의 정보가 주어진다. 미로는 1과 0, 그리고 S와 K로 주어

    www.acmicpc.net


     

    -풀이-

    1. 먼저 BFS를 이용하여 각각의 키마다 시작점->각각의 키 까지의 최단거리(가중치)를 구해준 뒤, edge에 추가를 해준다. 만약 시작점->키까지 갈 수 없는 키가 있다면, -1을 출력해준다.

    2. 각각의 키들끼리 BFS를 이용하여 최단거리(가중치)를 구해준 뒤, edge에 추가해준다.

    3. 모든 edge들을 구해주었으면, 크루스칼 알고리즘을 이용하여 mst를 만들어주며, 모든 가중치들의 합을 구해준 뒤 출력한다.

     

     

    -코드-

    #include <iostream>
    #include<queue>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    typedef pair<int, int> pii;
    
    char maze[50][50];
    int parent[251];
    bool visited[50][50] = { 0 };
    int n, m;
    vector<pair<pii, int>> edge;
    vector<pii> keys;
    int mv[4][2] = { {0,1},{0,-1},{1,0},{-1,0} };
    pair<int, int> st;
    
    bool compare(pair<pii, int> a, pair<pii, int> b) {
    	return a.second < b.second;
    }
    
    bool isIn(int i, int j) {
    	return 0 <= i && i < n && 0 <= j && j < n;
    }
    
    bool bfs(pii st,pii end,int v1,int v2) {
    	queue<pair<pair<int, int>, int>> q;
    	memset(visited, false, sizeof(visited));
    	q.push({ st,0 });
    	visited[st.first][st.second] = true;
    	while (!q.empty()) {
    		int x = q.front().first.first;
    		int y = q.front().first.second;
    		int t = q.front().second;
    
    		q.pop();
    
    		if (x == end.first&&y == end.second) {
    			edge.push_back({{v1,v2} ,t});
    			return true;
    		}
    		for (int i = 0; i < 4; i++) {
    			int nx = x + mv[i][0];
    			int ny = y + mv[i][1];
    
    			if (isIn(nx, ny) && !visited[nx][ny] && maze[nx][ny] != '1') {
    				q.push({ {nx,ny},t + 1 });
    				visited[nx][ny] = true;
    			}
    		}
    	}
    	return false;
    }
    
    void input() {
    	cin >> n >> m;
    	for (int i = 0; i < n; i++) {
    		for (int j = 0; j < n; j++) {
    			cin >> maze[i][j];
    			if (maze[i][j] == 'S') {
    				st = { i,j };
    			}
    			if (maze[i][j] == 'K') {
    				keys.push_back({ i,j });
    			}
    		}
    	}
    }
    
    int find(int a) {
    	if (a == parent[a]) {
    		return a;
    	}
    	else return find(parent[a]);
    }
    
    void union_parent(int a, int b) {
    	a = find(a);
    	b = find(b);
    	if (a < b) {
    		parent[b] = a;
    	}
    	else {
    		parent[a] = b;
    	}
    }
    
    int make_mst() {
    	int total_weight = 0;
    	for (int i = 0; i <= m; i++) {
    		parent[i] = i;
    	}
    	//가중치기준 오름차순 정렬
    	sort(edge.begin(), edge.end(), compare);
    
    	for (int i = 0; i < edge.size(); i++) {
    		int v1 = edge[i].first.first;
    		int v2 = edge[i].first.second;
    		int w = edge[i].second;
    
    		int pv1 = find(v1);
    		int pv2 = find(v2);
    		if (pv1 != pv2) {
    			union_parent(v1, v2);
    			total_weight += w;
    		}
    	}
    	return total_weight;
    }
    
    int solution() {
    	//정점->각 key들의 거리
    	for (int i = 0; i < keys.size(); i++) {
    		int kx = keys[i].first;
    		int ky = keys[i].second;
    		if (!bfs(st, { kx,ky },0,i+1)) {
    			return -1;
    		}
    	}
    	//키들간의 거리
    	for (int i = 0; i < keys.size(); i++) {
    		for (int j = i + 1; j < keys.size(); j++) {
    			int kx1 = keys[i].first;
    			int ky1 = keys[i].second;
    			int kx2 = keys[j].first;
    			int ky2 = keys[j].second;
    			bfs({ kx1,ky1 }, { kx2,ky2 }, i + 1, j + 1);
    		}
    	}
    	//mst구하기
    	return make_mst();
    }
    
    void solve() {
    	input();
    	cout << solution();
    }
    
    int main(){
    	ios::sync_with_stdio(false);
    	cin.tie(NULL);
    	cout.tie(NULL);
    	
    	solve();
    
    	return 0;
    }
    반응형

    댓글