본문 바로가기

백준/BFS

서울 지하철 2호선

728x90

서울 지하철 2호선은 다음과 같이 생겼다.

지하철 2호선에는 51개의 역이 있고, 역과 역 사이를 연결하는 구간이 51개 있다. 즉, 정점이 51개이고, 양방향 간선이 51개인 그래프로 나타낼 수 있다. 2호선은 순환선 1개와 2개의 지선으로 이루어져 있다. 한 역에서 출발해서 계속 가면 다시 출발한 역으로 돌아올 수 있는 노선을 순환선이라고 한다. 지선은 순환선에 속하는 한 역에서 시작하는 트리 형태의 노선이다.

두 역(정점) 사이의 거리는 지나야 하는 구간(간선)의 개수이다. 역 A와 순환선 사이의 거리는 A와 순환선에 속하는 역 사이의 거리 중 최솟값이다.

지하철 2호선과 같은 형태의 노선도가 주어졌을 때, 각 역과 순환선 사이의 거리를 구해보자.

입력

첫째 줄에 역의 개수 N(3 ≤ N ≤ 3,000)이 주어진다. 둘째 줄부터 N개의 줄에는 역과 역을 연결하는 구간의 정보가 주어진다. 같은 구간이 여러 번 주어지는 경우는 없고, 역은 1번부터 N번까지 번호가 매겨져 있다. 임의의 두 역 사이에 경로가 항상 존재하는 노선만 입력으로 주어진다.

출력

총 N개의 정수를 출력한다. 1번 역과 순환선 사이의 거리, 2번 역과 순환선 사이의 거리, ..., N번 역과 순환선 사이의 거리를 공백으로 구분해 출력한다.

 

#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#include<queue>
#include <map>
using namespace std;

int n;
bool circle = false;
int circlestart;

void findcircle(vector<vector<int>>&v,int idx, int elem,int *check) {

	int s = v[idx][elem];
	if (s == check[idx]) { return; }
	if (check[s] > 0 || check[s]==-1) { circlestart = s; check[s] = idx; circle = true; return; }
	check[s] = idx;
	idx = s;
	for (int i = 0; i < v[idx].size(); i++) {
		findcircle(v, idx, i, check);
		if (circle == true) { break; }
	}
	return;

}

int finddiff(vector<vector<int>>&v, map<int,bool>&m,int yuk) {
	int count = 0;
	int check[3002]; 
	memset(check, 0, sizeof(check));
	queue<int>q;
	q.push(yuk);
	
	
	while (!q.empty()) {
	
		int search = q.front();
		q.pop();
		if (m[search] == true) { return check[search]; }
		for (int i = 0; i < v[search].size(); i++){
			
			if (check[v[search][i]] == 0) {
				check[v[search][i]] = check[search]+1;
				q.push(v[search][i]);
			}
		
		}
	}
	return count;
}


int main() {
	cin >> n;
	vector<vector<int> > v(n+1);
	vector<int> route;
	map<int, bool> m;
	int check[3002]; //3000까지고 3000을 참조하려면 적어도 3001 까지는 있어야한다. 
	memset(check, 0, sizeof(check));
	for (int i = 1; i <= n; i++) {
		int yuk1;
		int yuk2;
		cin >> yuk1;
		cin >> yuk2;
		v[yuk1].push_back(yuk2);
		v[yuk2].push_back(yuk1);
	}

	for (int i = 1; i <= n; i++) { //모든 노드에 대해서 탐색을 해야함 하지 않으면 틀린다고 나온다
			
			memset(check, 0, sizeof(check));
			check[i] = -1;
			circlestart = i;
			findcircle(v, i, 0, check);
			if (circle == true) { 
				int idx = circlestart;
				while (1) {
					if (m[idx] == false) {
						m[idx] = true;
						 idx = check[idx];}
					else { break; }
				}
			
				break;
			}
		
			circle = false;
		}
	
	for (int i = 1; i <= n; i++) {
	
		int res = finddiff(v,m,i);
		cout << res << " ";
	
	}
	cout << endl;
	return 0;
}

어떤 알고리즘 어떤 논리로 그 알고리즘을 썼는지 ?

- 간선리스트를 사용해서 인접한 노드의 관계를 정의했다. 

 - BFS, DFS 모두 사용하였다. dfs의 경우 순환역을 추적하기 위해서는 dfs를 사용했는데 깊이 탐색이 더 빠를 것 같다는 생각과 BFS는 주로 최솟값을 구하기 위해 사용 되기 때문에 dfs 탐색을 선택했다. 특정역의 순환역으로부터의 거리는 가장 짧은 거리를 구하는 것이므로 bfs 를 썼다. 

헷갈렸던점

- 헷갈렸던 것은 어떤 노드를 시작으로 탐색을 해야하는데 시작 노드를 1일때 부터 n일 때까지 모두 탐색해 봐야하는지 궁금 했다. 시작노드 1로만 해서 순환 영역 탐색할 때 테케는 다 통과 됐지만 제출을 하면 틀렸다고 나온다. 어떤 반례가 있는것 같은데 아직 그걸 찾지 못했다.

- 순환영역이 여러개일 수도 있는지 궁금했다. 문제의 의도는 순환영역이 1개일 때만 생각을 하는 것 같았다. 여러개가 아닐 이유가 뭔지에 대해서도 생각해 봐야 할 것 같다. 

- 막상 bfs dfs 동시 구현해야하니까 좀 머리가 아팠다. 

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

데스 나이트  (0) 2021.02.14
연구소  (0) 2021.02.10
뱀과 사다리 게임  (0) 2021.02.08
BFS 스페셜 저지  (0) 2021.01.15
육각보드  (0) 2021.01.13