반응형

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

 

9019번: DSLR

문제 네 개의 명령어 D, S, L, R 을 이용하는 간단한 계산기가 있다. 이 계산기에는 레지스터가 하나 있는데, 이 레지스터에는 0 이상 10,000 미만의 십진수를 저장할 수 있다. 각 명령어는 이 레지스�

www.acmicpc.net

 

BFS를 사용하여 해결하는 문제였습니다. 

수의 범위가 0 이상 10,000 미만의 십진수이기 때문에 visited 배열을 만들어서 방문 했던 값을 표시하면서 시간을 확보 했습니다. queue를 pair로 사용해서 int, string 함께 저장하여 해결하였습니다. 

 

string을 쓰지않고 char형 만으로 구현하는게 베스트인 문제입니다! (사실 string을 사용하면 시간초과가 나게끔 유도한 느낌의 문제였습니다.. ㅠㅠ) 

 

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

int t = 0;
int a = 0, b = 0;
bool visited[10000];
int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);

	cin >> t;

	string result;

	while (t--) {
		memset(visited, 0, sizeof(visited));

		result = "";

		cin >> a >> b;
		queue <pair<int, string>> que;
		// 0 -> D 1 -> S 2 -> L 3 -> R
		que.push(make_pair(a, ""));
		visited[a] = 1;
		string word;
		while (!que.empty()) {

			int num = que.front().first;
			word = que.front().second;
			que.pop();
			
			if (num == b) {
				result = word;
				break;
			}

			int verifed_num = (num * 2) % 10000;
			if(!visited[verifed_num])
				que.push(make_pair(verifed_num, word + "D")), visited[verifed_num] = 1;
			
			if (num == 0 && !visited[9999]) que.push(make_pair(9999, word + "S")), visited[9999] = 1;
			else if(!visited[num - 1])que.push(make_pair(num - 1, word + "S")), visited[num - 1] = 1;
			
			verifed_num = (num % 1000) * 10 + (num / 1000);
			if (!visited[verifed_num])
				que.push(make_pair(verifed_num, word + "L")), visited[verifed_num] = 1;
			verifed_num = (num / 10) + (num % 10) * 1000;
			if (!visited[verifed_num])
				que.push(make_pair(verifed_num, word + "R")), visited[verifed_num] = 1;

		}

		cout << result << "\n";
	}

}
반응형

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

[백준] 2606- 바이러스(C++)  (0) 2021.02.06
[백준] 1261-알고스팟(C++)  (0) 2020.08.25
[백준] 6593-상범 빌딩(C++)  (0) 2020.07.03
[백준] 4179-불!(C++)  (0) 2020.05.06
[백준] 5427-불(C++)  (0) 2020.05.06
반응형

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

 

6593번: 상범 빌딩

문제 당신은 상범 빌딩에 갇히고 말았다. 여기서 탈출하는 가장 빠른 길은 무엇일까? 상범 빌딩은 각 변의 길이가 1인 정육면체(단위 정육면체)로 이루어져있다. 각 정육면체는 금으로 이루어져

www.acmicpc.net

 

BFS, DFS 문제입니다! 근데 이 문제는 DFS 풀이법을 허용하지 않았습니다. 

최단거리를 구할때는 BFS를 사용하는 습관을 가져야겠습니다.

 

 

기본적인 BFS문제입니다. 기존에는 4방향으로 이동하지만 6방향으로  이동한다는 차이점만 있습니다. 

토마토 6방향문제와 동일한 문제입니다.

 

너무 일반적인 문제라 설명은 생략하겠습니다.

 

 

정답코드입니다.

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

int l = 0, r = 0, c = 0;
int result;
char arr[31][31][31];
int visited[31][31][31];
int y_ar[6] = { 0, 0, 1, -1, 0, 0 };
int x_ar[6] = { 0, 0, 0, 0, 1, -1 };
int z_ar[6] = { 1, -1, 0, 0, 0, 0 };



void bfs(int sz,int sy,int sx) {
	
	queue <int> que[3];
	que[0].push(sz);
	que[1].push(sy);
	que[2].push(sx);
	visited[sz][sy][sx] = 1;
	while (que[0].empty() != 1) {


		int zz = que[0].front();
		int yy = que[1].front();
		int xx = que[2].front();
		que[0].pop(), que[1].pop(), que[2].pop();
		
		for (int i = 0; i < 6; i++) {
			int z = zz + z_ar[i];
			int y = yy + y_ar[i];
			int x = xx + x_ar[i];

			if (z >= 0 && z < l && y >= 0 && y < r && x >= 0 && x < c)
				if (visited[z][y][x] == 0 && arr[z][y][x] != '#') {
					visited[z][y][x] = visited[zz][yy][xx] + 1;
					que[0].push(z);
					que[1].push(y);
					que[2].push(x);
				}
		}
	}

	for (int i = 0; i < l; i++)
		for (int j = 0; j < r; j++)
			for (int k = 0; k < c; k++)
				if (arr[i][j][k] == 'E')
					result = visited[i][j][k];



}

int main() {
	cin.tie(NULL);
	ios::sync_with_stdio(false);

	while (1) {
		cin >> l >> r >> c;
		if (l == 0 && r == 0 && c == 0)
			break;

		memset(visited, 0, sizeof(visited));

		result = (int)2e9;
		int sz, sy, sx;

		for (int i = 0; i < l; i++)
			for (int j = 0; j < r; j++) {
				cin >> arr[i][j];

				for (int k = 0; k < c; k++) {
					if (arr[i][j][k] == 'S')
						sz = i, sy = j, sx = k;
				}
			}
	
		bfs(sz, sy, sx);
		

		if (result == 0)
			cout << "Trapped!" <<"\n";
		else
			cout << "Escaped in " << result  - 1<< " minute(s)." <<"\n";
	}

	return 0;
}

 

반응형

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

[백준] 1261-알고스팟(C++)  (0) 2020.08.25
[백준] 9019-DSLR  (0) 2020.08.10
[백준] 4179-불!(C++)  (0) 2020.05.06
[백준] 5427-불(C++)  (0) 2020.05.06
[백준] 2206-벽 부수고 이동하기(C++)  (0) 2020.04.03
반응형

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

 

4179번: 불!

문제 지훈이는 미로에서 일을 한다. 지훈이를 미로에서 탈출하도록 도와주자! 미로에서의 지훈이의 위치와 불이 붙은 위치를 감안해서 지훈이가 불에 타기전에 탈출할 수 있는지의 여부, 그리��

www.acmicpc.net

 

5427번 불의 이전단계 문제입니다.

 

알고리즘은

  • 1. 불먼저 전파
  • 2. 사람 이동
  • 1, 2번을 사람이 이동가능한 칸이 있을 때 까지 반복
  • 3. 결과 값 도출

순입니다.

 

#include <iostream>
#include <queue>
#include <cstring>
#include <string>
using namespace std;
int h = 0, w = 0;
int visited[1000][1000] = { 0 };
char arr[1000][1000];

queue <int> fire[2];
queue <int> people[2];

int x_ar[4] = { -1,1,0,0 };
int y_ar[4] = { 0,0,1,-1 };

void bfs() {
	//초기값 입력
	for (int i = 0; i < h; i++)
		for (int j = 0; j < w; j++)
			if (arr[i][j] == 'F')
				fire[0].push(i), fire[1].push(j);
			else if (arr[i][j] == 'J')
				people[0].push(i), people[1].push(j), visited[i][j] = 1;



	while (!people[0].empty()) { //상근이가 이동할 경로가 없을 때 까지 반복
								 //1. 불먼저 전파
		int fire_cnt = fire[0].size();
		while (fire_cnt--) {
			int yy = fire[0].front();
			int xx = fire[1].front();
			fire[0].pop(), fire[1].pop();
			for (int i = 0; i < 4; i++) {
				int y = yy + y_ar[i];
				int x = xx + x_ar[i];
				if (y >= 0 && y < h && x >= 0 && x < w)
					if (arr[y][x] == '.' || arr[y][x] == 'J') {
						arr[y][x] = 'F';
						fire[0].push(y), fire[1].push(x);
					}
			}
		}
		//2. 상근좌 이동
		int people_cnt = people[0].size();
		while (people_cnt--) {
			int yy = people[0].front();
			int xx = people[1].front();
			people[0].pop(), people[1].pop();
			for (int i = 0; i < 4; i++) {
				int y = yy + y_ar[i];
				int x = xx + x_ar[i];
				if (y >= 0 && y < h && x >= 0 && x < w)
					if (arr[y][x] == '.' && visited[y][x] == 0) {
						visited[y][x] = visited[yy][xx] + 1;
						people[0].push(y), people[1].push(x);
					}
			}
		}
	}
	//3. 모서리의 visited값들을 확인하고 결과값을 도출
	int result = 1000000;
	bool alive = false;
	for (int i = 0; i < h; i++) {
		if (visited[i][0] != 0) {
			alive = true;
			if (visited[i][0] < result)
				result = visited[i][0];
		}
		if (visited[i][w - 1] != 0) {
			alive = true;
			if (visited[i][w - 1] < result)
				result = visited[i][w - 1];
		}
	}
	for (int j = 0; j < w; j++) {
		if (visited[0][j] != 0) {
			alive = true;
			if (visited[0][j] < result)
				result = visited[0][j];
		}
		if (visited[h - 1][j] != 0) {
			alive = true;
			if (visited[h - 1][j] < result)
				result = visited[h - 1][j];
		}
	}

	if (alive)
		cout << result << '\n';
	else
		cout << "IMPOSSIBLE" << '\n';
}

int main() {

	cin >> h >> w;
	for (int i = 0; i < h; i++) {
		string val;
		cin >> val;
		for (int j = 0; j < val.size(); j++)
			arr[i][j] = val[j];
	}
	bfs();

}

비슷한 유형문제를 풀어보셨다면 어렵지 않습니다.

꼭 이 문제 직접구현해보시고 bfs에 익숙해지세요! 화이팅

 

 

 

반응형

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

[백준] 9019-DSLR  (0) 2020.08.10
[백준] 6593-상범 빌딩(C++)  (0) 2020.07.03
[백준] 5427-불(C++)  (0) 2020.05.06
[백준] 2206-벽 부수고 이동하기(C++)  (0) 2020.04.03
[백준] 8061-Bitmap  (0) 2020.03.26
반응형

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

 

5427번: 불

문제 상근이는 빈 공간과 벽으로 이루어진 건물에 갇혀있다. 건물의 일부에는 불이 났고, 상근이는 출구를 향해 뛰고 있다. 매 초마다, 불은 동서남북 방향으로 인접한 빈 공간으로 퍼져나간다. 벽에는 불이 붙지 않는다. 상근이는 동서남북 인접한 칸으로 이동할 수 있으며, 1초가 걸린다. 상근이는 벽을 통과할 수 없고, 불이 옮겨진 칸 또는 이제 불이 붙으려는 칸으로 이동할 수 없다. 상근이가 있는 칸에 불이 옮겨옴과 동시에 다른 칸으로 이동할 수 있다. 빌딩

www.acmicpc.net

 

 bfs문제입니다.

불과 상근이가 함께 이동하기 때문에 각각 bfs를 사용해서 구현하시면 되는 문제입니다.

 

 

문제조건에서 

상근이는 벽을 통과할 수 없고, 불이 옮겨진 칸 또는 이제 불이 붙으려는 칸으로 이동할 수 없다. 상근이가 있는 칸에 불이 옮겨옴과 동시에 다른 칸으로 이동할 수 있다.

이라고 하기 때문에 불을 먼저 움직여주면 됩니다.

 

알고리즘은

  • 1. 불먼저 전파
  • 2. 상근좌 이동
  • 1, 2번을 상근좌가 이동가능한 칸이 있을 때 까지 반복
  • 3. 결과 값 도출

순입니다.

 

 

 

 

 

 

정답코드입니다.

#include <iostream>
#include <queue>
#include <cstring>
#include <string>
using namespace std;
int t = 0, h = 0, w = 0;
int visited[1000][1000] = { 0 };
char arr[1000][1000];

queue <int> fire[2];
queue <int> people[2];

int x_ar[4] = { -1,1,0,0 };
int y_ar[4] = { 0,0,1,-1 };

void bfs() {
	//초기값 입력
	for (int i = 0; i < h; i++)  
		for (int j = 0; j < w; j++)
			if (arr[i][j] == '*')
				fire[0].push(i), fire[1].push(j);
			else if(arr[i][j] == '@')
				people[0].push(i), people[1].push(j), visited[i][j] = 1;

	

	while (!people[0].empty()) { //상근이가 이동할 경로가 없을 때 까지 반복
		//1. 불먼저 전파
		int fire_cnt = fire[0].size();
		while (fire_cnt--) {
			int yy = fire[0].front();
			int xx = fire[1].front();
			fire[0].pop(), fire[1].pop();
			for (int i = 0; i < 4; i++) {
				int y = yy + y_ar[i];
				int x = xx + x_ar[i];
				if (y >= 0 && y < h && x >= 0 && x < w) 
					if (arr[y][x] == '.' || arr[y][x] == '@') {
						arr[y][x] = '*';
						fire[0].push(y), fire[1].push(x);
					}
			}
		}
		//2. 상근좌 이동
		int people_cnt = people[0].size();
		while (people_cnt--) {
			int yy = people[0].front();
			int xx = people[1].front();
			people[0].pop(), people[1].pop();
			for (int i = 0; i < 4; i++) {
				int y = yy + y_ar[i];
				int x = xx + x_ar[i];
				if (y >= 0 && y < h && x >= 0 && x < w)
					if (arr[y][x] == '.' && visited[y][x] == 0) {
						visited[y][x] = visited[yy][xx] + 1;
						people[0].push(y), people[1].push(x);
					}
			}
		}
	}
	//3. 모서리의 visited값들을 확인하고 결과값을 도출
	int result = 1000000;
	bool alive = false;
	for (int i = 0; i < h; i++) {
		if (visited[i][0] != 0) {
			alive = true;
			if (visited[i][0] < result)
				result = visited[i][0];
		}
		if (visited[i][w - 1] != 0) {
			alive = true;
			if (visited[i][w - 1] < result)
				result = visited[i][w - 1];
		}
	}
	for (int j = 0; j < w; j++) {
		if (visited[0][j] != 0) {
			alive = true;
			if (visited[0][j] < result)
				result = visited[0][j];
		}
		if (visited[h - 1][j] != 0) {
			alive = true;
			if (visited[h - 1][j] < result)
				result = visited[h - 1][j];
		}
	}

	if (alive)
		cout << result << '\n';
	else
		cout << "IMPOSSIBLE" << '\n';
}

int main() {
	cin >> t;

	while (t--) {
		memset(visited, 0, sizeof(visited));
		while (!fire[0].empty())
			fire[0].pop(), fire[1].pop();

		cin >> w >> h;
		for (int i = 0; i < h; i++) {
			string val;
			cin >> val;
			for (int j = 0; j < val.size(); j++)
				arr[i][j] = val[j];
		}
		bfs();
	}
}

비슷한 유형문제를 풀어보셨다면 어렵지 않습니다.

꼭 이 문제 직접구현해보시고 bfs에 익숙해지세요! 화이팅

반응형

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

[백준] 6593-상범 빌딩(C++)  (0) 2020.07.03
[백준] 4179-불!(C++)  (0) 2020.05.06
[백준] 2206-벽 부수고 이동하기(C++)  (0) 2020.04.03
[백준] 8061-Bitmap  (0) 2020.03.26
[백준] 1389-케빈 베이컨의 6단계 법칙(C++)  (0) 2020.03.22
반응형

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

 

2206번: 벽 부수고 이동하기

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로로 이동하려 한다. 최단경로는 맵에서 가장 적은 개수의 칸을 지나는 경로를 말하는데, 이때 시작하는 칸과 끝나는 칸도 포함해서 센다. 만약에 이동하는 도중에 한 개의 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 한 개 까지 부수고 이동

www.acmicpc.net

 

bfs문제입니다.

근데 기존의 bfs와 다른점은 벽을 한번 부수고 갈 수 있다는 점입니다. 

 

처음으로 생각하셔야 할 것은 각 점마다 벽을 뚫고 이동하는 최단경로와 벽을 뚫지 않고 이동하는 최단경로를 고려해주어야 한다는 점입니다. (1)

 

두번째로 생각하셔야 할 것은 최단거리검색이라는 점입니다. 그렇기 때문에 방문한 곳이라면 굳이 다시 방문할 필요가 없다는 것을 인지하셔야 합니다. (이 점은 기존 bfs와 같습니다.) (2)

 

1. 벽이 아니고 현재 방문한적이 없을 때 ( 벽을 뚫고 방문한 것과 벽을 뚫지 않고 도착한 것 두가지를 모두 고려해주어야 합니다. 왜냐하면 이미 벽을 뚫고 도착해서 최단경로값을 표시하는 경우가 있기 때문입니다.)

     1) 큐에 좌표와 벽부수기가능여부를 넣어줍니다.

     2) 최단거리값에 1더해주기 

 

2. 벽이고 뚫을 수 있을 때 (벽을 뚫은 적이 있다면 더이상 벽을 뚫을 수 없고, 뚫은 적이 없을 경우 해당 벽을 뚫고 벽을 뚫은 최단경로에 포함시켜줍니다. )

     1) 큐에 좌표와 불가능을 넣어줍니다.

     2) 벽을 뚫은 최단거리에 기존 벽뚫기 전 최단거리값에 1을 더해 넣어줍니다. 

 

테스트 케이스

8 8
01000100
01010100
01010100
01010100
01010100
01010100
01010100
00010100

 

5 8
01000000
01010000
01010000
01010011
00010010

 

 

정답코드입니다.

#include <iostream>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
int n = 0, m = 0;
bool arr[1001][1001] = { 0 }; // 0 1을 저장하는 배열 
int  visited[1001][1001][2] = { 0 }; // 방문거리 
string v; // 문자열로 받고 arr에 다시 넣기위해 쓰는 변수 
queue<int> que[3]; //y,x,벽가능여부 

int x_ar[4] = { 1,0,-1, 0};
int y_ar[4] = { 0,1,0,-1 };

void bfs() {
	visited[1][1][1] = 1;
		
	que[0].push(1); //y
	que[1].push(1); //x
	que[2].push(1); // 벽뚫기 가능

	while (que[0].empty() != true) { // 큐가 빌때 까지 반복합니다. 
		int yy = que[0].front();
		int xx = que[1].front();
		int talent = que[2].front(); //1이면  벽뚫기 가능
		que[0].pop();
		que[1].pop();
		que[2].pop(); 

		for (int i = 0; i < 4; i++) {
			int y = yy + y_ar[i];
			int x = xx + x_ar[i];
			if (y >= 1 && y <= n && x >= 1 && x <= m) { // 배열범위에 포함되는지 확인 
				if (arr[y][x] == 0 && visited[y][x][talent] == 0) {//벽이 아니고 방문한 적 없을때
					que[0].push(y); //y
					que[1].push(x); //x
					que[2].push(talent); // 벽뚫기 가능
					visited[y][x][talent] = visited[yy][xx][talent] + 1;
				}
				else if (arr[y][x] == 1 && talent == 1) { //벽이고 아직 안 뚫었을때 
					visited[y][x][talent - 1] =  visited[yy][xx][talent] + 1;
					que[0].push(y); //y
					que[1].push(x); //x
					que[2].push(0); //벽을 더이상 뚫지 못한다. 
				}
			}

		}


	}

}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> v;
		for (int j = 1; j <= m; j++)
			if (v[j-1] == '1')
				arr[i][j] = 1;
	}


	bfs(); 
	
	
	if (visited[n][m][1] == 0 && visited[n][m][0] == 0)
		cout << -1 << '\n';
	else if(visited[n][m][1] != 0 && visited[n][m][0] != 0)
		cout << min(visited[n][m][0], visited[n][m][1]) << '\n';
	else
		if(visited[n][m][1] == 0)
			cout << visited[n][m][0] << '\n';
		else
			cout << visited[n][m][1] << '\n';
}

 

반응형

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

[백준] 4179-불!(C++)  (0) 2020.05.06
[백준] 5427-불(C++)  (0) 2020.05.06
[백준] 8061-Bitmap  (0) 2020.03.26
[백준] 1389-케빈 베이컨의 6단계 법칙(C++)  (0) 2020.03.22
[백준] 9205-맥주 마시면서 걸어가기(C++)  (0) 2020.03.12
반응형

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

 

8061번: Bitmap

First line of the standard input there is a pair of integer numbers n, m separated by a single space, 1 ≤ n ≤ 182, 1 ≤ m ≤ 182. In each of the following n lines of the input exactly one zero-one word of length m, the description of one line of the bitmap,

www.acmicpc.net

 

전형적인 bfs 문제입니다. d(p1,p2)=|i1-i2|+|j1-j2| 을 만족하는 최단 경로 탐색문제입니다.

너무 쉬워서 설명은 생략하겠습니다.

 

#include <iostream>
#include <cstring>
#include <string>
using namespace std;
int n = 0, m = 0;
int arr[183][183] = { 0 };
int visited[183][183] = { 0 };
int que[40000][2] = { 0 };
int started = 0, ended = 0;
int x_go[4] = { 0,0,1,-1 };
int y_go[4] = { 1,-1,0,0 };

void bfs() {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			if (arr[i][j] == 1)
				que[ended][0] = i, que[ended++][1] = j, visited[i][j] = 1;

	while (started != ended) {
		int y = que[started][0];
		int x = que[started++][1];

		for (int i = 0; i < 4; i++) {
			int yyy = y + y_go[i];
			int xxx = x + x_go[i];
			if (yyy >= 0 && yyy < n && xxx >= 0 && xxx < m)
				if (!visited[yyy][xxx]) {
					visited[yyy][xxx] = visited[y][x] + 1;
					que[ended][0] = yyy, que[ended++][1] = xxx;
				}
		}
	}
}

int main() {
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		string arg;
		cin >> arg;
		for (int j = 0; j < m; j++) {
			arr[i][j] = arg[j] - '0';

		}
	}

	bfs();
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++)
			cout << visited[i][j] - 1 << ' ';
		cout << '\n';
	}
}

 

 그리고 조금더 오래걸리지만 브루트포스의 형식으로도 solve를 받을 수 있습니다.

장점: 쉬운 문제풀이 단점: 시간 

#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;
int n = 0, m = 0;
int arr[183][183] = { 0 };
int visited[183][183] = { 0, };
int que[40000][2] = { 0 };
int ended = 0;

void func() {
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			if (arr[i][j] == 1)
				que[ended][0] = i, que[ended++][1] = j;

	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++) {
			int y = i, x = j;

			for (int k = 0; k < ended; k++) {
				if (arr[y][x] == 0) {
					int val = abs(y - que[k][0]) + abs(x - que[k][1]);
					if (visited[y][x] > val) {
						visited[y][x] = val;
					}
				}
			}

		}

}

int main() {
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		string arg;
		cin >> arg;
		for (int j = 0; j < m; j++) {
			arr[i][j] = arg[j] - '0';
			if (arr[i][j] == 0)
				visited[i][j] = 1000;
		}
	}

	func();
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++)
			cout << visited[i][j] << ' ';
		cout << '\n';
	}
}
반응형
반응형

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

 

1389번: 케빈 베이컨의 6단계 법칙

첫째 줄에 유저의 수 N (2 ≤ N ≤ 100)과 친구 관계의 수 M (1 ≤ M ≤ 5,000)이 주어진다. 둘째 줄부터 M개의 줄에는 친구 관계가 주어진다. 친구 관계는 A와 B로 이루어져 있으며, A와 B가 친구라는 뜻이다. A와 B가 친구이면, B와 A도 친구이며, A와 B가 같은 경우는 없다. 친구 관계는 중복되어 들어올 수도 있으며, 친구가 한 명도 없는 사람은 없다. 또, 모든 사람은 친구 관계로 연결되어져 있다.

www.acmicpc.net

 

6다리면 건너면 세상사람들을 다 알 수 있다~ 이런 느낌의 문제였습니다.

당연히 탐색이라면 dfs, bfs를 먼저 생각하셔야 합니다.  문제 조건으로 유저의 수 N (2 ≤ N ≤ 100)과 친구 관계의 수 M (1 ≤ M ≤ 5,000)입니다. 비교적 큰 수이기 때문에 dfs보다는 bfs를 먼저 생각했습니다. 

 

각각의 n번에서 최적탐색을 통해서 가장 빨리 도달하는 관계의 합을 더해주면 되는 방식이였습니다.

 

 

 

 

정답코드입니다.  bfs코드이고 4ms 정도의 시간이 걸립니다. 풀면서도 살짝 긴가민가 했습니다.

왜냐하면 O(n*m*n*큐)이고  대략 50,000,000 이상의 반복연산을 하기때문입니다. 1억번에는 훨씬 못미치지만 반복을 재외한 큐이므로 큐자체도 100번은 반복하지 않을까하는 생각때문입니다.

다행히 문제는 통과했습니다. ( 1초에 1억번이라는게 정확한 연산은 아니기도 하고 큐에 대해서 제가 놓치고 있는 부분이 있기에 통과된것같습니다.)

#include <iostream>
#include <cstring>
using namespace std;

int n = 0, m = 0;
int arr[5001][2];
int visited[5001];
int result = 1000000000,result_index =-1;
int bfs(int num) {
	int val = 0;
	int que[5000];
	
	for (int i = 1; i <= n; i++) {
		if (num == i) continue;
		memset(que, 0, 5000);
		memset(visited, 0, 5001);
		int started = 0, ended = 0;

		que[ended++] = num;
		visited[num] = 1;
		while (ended != started) {
			int a = que[started++];
			if (a == i) {
				val += visited[a] - 1;
				break;
			}
			for (int j = 0; j < m; j++) {
				if (arr[j][0] == a && !visited[arr[j][1]]) {
					que[ended++] = arr[j][1];
					visited[arr[j][1]] = visited[a] + 1;
				}
				else if (arr[j][1] == a && !visited[arr[j][0]]) {
					que[ended++] = arr[j][0];
					visited[arr[j][0]] = visited[a] + 1;
				}
			}
			

		}
	}

	return val;
}

int main() {
	cin >> n >> m;
	for (int i = 0; i < m; i++)
		cin >> arr[i][0] >> arr[i][1];


	for (int i = 1; i <= n; i++) { //1~n번까지의 경로를 탐색
		int val = bfs(i);
		if (result > val) result = val, result_index = i;
	}
	cout << result_index << endl;
}

 

근데 생각해보니 더욱 효율적인 방법이 있었습니다. 

굳이 bfs문에서 n번 반복해줄 필요가 없었습니다...

어차피 while문이 한번다 돌고나면 visited엔 모든 인덱스별 최단경로값이 들어가있게 됩니다. 

친구 관계는 중복되어 들어올 수도 있으며, 친구가 한 명도 없는 사람은 없다. 또, 모든 사람은 친구 관계로 연결되어져 있다.

이 문제조건 때문입니다.

 

수정코드입니다.

시간도 0ms로 줄었습니다. 

#include <iostream>
#include <cstring>
using namespace std;

int n = 0, m = 0;
int arr[5001][2];
int visited[5001];
int result = 1000000000,result_index =-1;
int bfs(int num) {
	int val = 0;
	int que[5000];


	memset(que, 0, 5000);
	memset(visited, 0, 5001);
	int started = 0, ended = 0;

	que[ended++] = num;
	visited[num] = 1;
	while (ended != started) {
		int a = que[started++];

		for (int j = 0; j < m; j++) {
			if (arr[j][0] == a && !visited[arr[j][1]]) {
				que[ended++] = arr[j][1];
				visited[arr[j][1]] = visited[a] + 1;
			}
			else if (arr[j][1] == a && !visited[arr[j][0]]) {
				que[ended++] = arr[j][0];
				visited[arr[j][0]] = visited[a] + 1;
			}
		}

	}

	for (int i = 1; i <= n; i++)
		val += visited[i] - 1;


	return val;
	
}

int main() {
	cin >> n >> m;
	for (int i = 0; i < m; i++)
		cin >> arr[i][0] >> arr[i][1];


	for (int i = 1; i <= n; i++) { //1~n번까지의 경로를 탐색
		int val = bfs(i);
		if (result > val) result = val, result_index = i;
	}
	cout << result_index << endl;
}

 

 

dfs코드입니다. 다른 분의 코드를 참고해서 만들었습니다. 216ms로 시간이 오래걸립니다. 어느 것이 더욱 좋다 이 것보다는 자기한테 편한코드로 ac를 받으면 되는거라고 생각합니다. dfs의 장점은 명료하고 직관적이라는 것입니다. 다음뻔에는 dfs로 풀어야하는 문제를 리뷰하겠습니다. 모두 화이팅 :) 

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define MAX 102
#define INF 987654321
using namespace std;

int n,m;
int a,b;
int ans,res,step;
int person;

bool check[MAX];
vector<int> v[MAX];

void dfs(int ind,int goal,int cnt){
    if(ind == goal){
        step = min(step,cnt);
        return;
    }
    for(int i=0; i<v[ind].size(); i++){
        if(!check[v[ind][i]]){
            check[ind] = true;
            dfs(v[ind][i],goal,cnt+1);
            check[ind] = false;
        }
    }
}

int main(int argc, const char * argv[]) {
    // cin,cout 속도향상
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    // 입력
    cin >> n >> m;
    for(int i=0; i<m; i++){
        cin >> a >> b;
        v[a].push_back(b);
        v[b].push_back(a);
    }
    // 탐색
    ans = INF;
    for(int i=1; i<=n; i++){
        memset(check, false, sizeof(check));
        res = 0;
        for(int j=1; j<=n; j++){
            step = INF;
            if(i==j) continue;
            else{
                dfs(i,j,0);
                res += step;
            }
        }
        // 최소인지 검사
        if(ans > res){
            ans = res;
            person = i;
        }else if(ans == res){
            person = min(person, i);
        }
    }
    cout << person << endl;
}
반응형

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

[백준] 2206-벽 부수고 이동하기(C++)  (0) 2020.04.03
[백준] 8061-Bitmap  (0) 2020.03.26
[백준] 9205-맥주 마시면서 걸어가기(C++)  (0) 2020.03.12
[백준] 5014-스타트링크(C++)  (1) 2020.03.12
[백준] 2589-보물섬(C++)  (0) 2020.03.08
반응형

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

 

9205번: 맥주 마시면서 걸어가기

문제 송도에 사는 상근이와 친구들은 송도에서 열리는 펜타포트 락 페스티벌에 가려고 한다. 올해는 맥주를 마시면서 걸어가기로 했다. 출발은 상근이네 집에서 하고, 맥주 한 박스를 들고 출발한다. 맥주 한 박스에는 맥주가 20개 들어있다. 목이 마르면 안되기 때문에 50미터에 한 병씩 마시려고 한다. 상근이의 집에서 페스티벌이 열리는 곳은 매우 먼 거리이다. 따라서, 맥주를 더 구매해야 할 수도 있다. 미리 인터넷으로 조사를 해보니 다행히도 맥주를 파는 편의

www.acmicpc.net

 

문제접근을 하는데 어려움을 겪었습니다.

처음에 가진 생각은 가장 이동경로내에 여러개의 편의점이 있으면 어디를 선택할까와 같은 생각을 했지만, 다시 생각해보니 무의미했습니다. yes, no로 도달할 수 있는지만 판단하면 되었기 때문입니다. 그렇기 때문에 모든 편의점을 탐색하며 도달할 수 있는지 여부만 판단했습니다.

 

bfs알고리즘을 사용해서 방문여부를 판단했습니다.

주의 하셔야 할 점은  두 좌표 사이의 거리는 x 좌표의 차이 + y 좌표의 차이 이다. (맨해튼 거리) 입니다.

문제를 꼼꼼히 읽는 습관을 가져야 합니다.

 

아래는 정답코드입니다.

#include <iostream>
#include <cstring>
#include <algorithm>
#include <math.h>
using namespace std;
int t = 0, n = 0;
int arr[101][2] = { 0 };
int starting_x, starting_y, destination_x, destination_y;
bool visited[101];
int que[1000000][2] = { 0 };
int started = 0, ended = 0;

void bfs() {
	que[ended][0] = starting_y;
	que[ended++][1] = starting_x;

	while (started != ended) {
		int y = que[started][0];
		int x = que[started++][1];

		for (int i = 0; i <= n; i++) {
			if (!visited[i]) {
				int len_x = min(abs(x - arr[i][1]), abs(arr[i][1] - x));
				int len_y = min(abs(y - arr[i][0]), abs(arr[i][0] - y));
				double len_total = len_x + len_y;
				if (len_total <= 1000)
				{
					visited[i] = 1;
					que[ended][0] = arr[i][0];
					que[ended++][1] = arr[i][1];
				}
				
			}
		}
	}

}
int main() {
	cin >> t;

	while (t--) {
		cin >> n;
		cin >> starting_x >> starting_y;
		for (int i = 0; i < n; i++)
			cin >> arr[i][1] >> arr[i][0];
		cin >> arr[n][1] >> arr[n][0];

		memset(visited, 0, sizeof(visited));
		started = 0, ended = 0;

		bfs();
		if (visited[n])
			cout << "happy" << endl;
		else
			cout << "sad" << endl;
	}


}
반응형

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

[백준] 8061-Bitmap  (0) 2020.03.26
[백준] 1389-케빈 베이컨의 6단계 법칙(C++)  (0) 2020.03.22
[백준] 5014-스타트링크(C++)  (1) 2020.03.12
[백준] 2589-보물섬(C++)  (0) 2020.03.08
[백준] 2644-촌수계산(C++)  (0) 2020.03.08

+ Recent posts