dev_beomgeun
꾸준하게 차근차근
dev_beomgeun
전체 방문자
오늘
어제
  • 분류 전체보기 (170)
    • 전공 (0)
      • 운영체제 (0)
      • 알고리즘 (0)
      • 자료구조 (0)
      • 데이터베이스 (0)
      • 네트워크 (0)
    • 개발 공부 (32)
      • 웹 (6)
      • 리눅스 (4)
      • 머신러닝 (1)
      • 스프링 (17)
      • Git (2)
      • AWS (2)
    • 개발 도서, 강의 (3)
      • 스프링 입문을 위한 자바 객체지향의 원리와 이해 (0)
      • 모든 개발자를 위한 HTTP 웹 기본 지식(김영한.. (2)
      • 스프링 부트와 AWS로 혼자 구현하는 웹서비스 (1)
    • 문제 풀이 (118)
      • 백준 알고리즘 (72)
      • 프로그래머스 알고리즘, SQL (38)
      • Hackerrank SQL (8)
    • 프로젝트 기록 (4)
      • 캡스톤 종합설계 (4)
      • 반려하루 프로젝트 (0)
    • 활동 기록 (12)
      • 네이버 부스트캠프 (7)
      • 취준 & 코테 (4)
      • 소프트웨어 마에스트로 13기 (1)
    • 이것저것 (1)

블로그 메뉴

  • 홈
  • 깃허브
  • 링크드인
  • 방명록

공지사항

인기 글

태그

  • Hackerrank
  • 프로그래머스
  • 네이버 부스트캠프
  • 부스트캠프
  • 서블릿
  • 프로그래머스 SQL
  • dp
  • AI Tech
  • 그래프탐색
  • HackerRank mysql
  • c++
  • 기록
  • BFS
  • 백준 DP
  • 일기
  • 회고
  • 반성
  • 백준
  • Baekjoon
  • 스프링

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
dev_beomgeun

꾸준하게 차근차근

문제 풀이/백준 알고리즘

[baekjoon 2146] 다리 만들기 (그래프, BFS) (C++)

2021. 2. 8. 19:01
728x90

www.acmicpc.net/problem/2146

 

2146번: 다리 만들기

여러 섬으로 이루어진 나라가 있다. 이 나라의 대통령은 섬을 잇는 다리를 만들겠다는 공약으로 인기몰이를 해 당선될 수 있었다. 하지만 막상 대통령에 취임하자, 다리를 놓는다는 것이 아깝다

www.acmicpc.net

주어진 섬들 중에 최단 경로를 구하면 되는 문제이다. 

처음에 어떻게 풀면 할까, 하다가 N이 최대 100이길래 완전 탐색 느낌으로 거리를 구하면 되겠다.라고 생각했다.

 

내 풀이법은 일단

1. BFS를 통해서 연결된 섬에 대한 정보를 얻는다.

2. 이후에 vector<pair<int, int>> v[5001]의 2차원 벡터에 땅 하나에 맞춰서 벡터에 좌표를 넣어준다.

ex) 첫 번째 BFS 수행 -> 첫 번째 땅 탐색이므로 v[0]에 좌표값들 (1,1), (1,2) 등을 넣어준다.

 

3. 그렇게 섬에 대한 정보를 저장한 다음에, 섬의 좌표들끼리 거리를 계산해서 최솟값을 출력하는 것이다.

4중 for문으로 약간 무식하게 풀었지만, N이 작기 때문에 오히려 다른 풀이들보다 0.52ms로 시간도 괜찮게 나왔다.

ex) 첫 번째 땅과 두 번째 땅끼리 최단거리 비교(v[0]과 v[1]에 저장된 pair 좌표들끼리 계산)

-> 첫 번째 땅과 세 번째 땅 계산 ... 마지막 땅까지

-> 두 번째부터 마지막까지... N-1 땅에서 N까지 계산해준다.

 

+ BFS 함수 마지막 부분에서

			if (!check[x][y] && field[x][y]) {
				if (x >= 0 && y >= 0 && x < N && y < N) {
					q.push(make_pair(x, y));
					check[x][y] = true;
					int temp = 1;
					for (int i = 0; i < 4; i++) {
						int xX = x + xmove[i];
						int yY = y + ymove[i];
						if(xX >= 0 && yY >= 0 && xX < N && yY < N)
							temp *= field[xX][yY];
					}
					if(temp == 0)
						v[cnt].push_back(make_pair(x, y));

 원래는 그냥 모조리 v[cnt]에 섬의 좌표를 넣었는데, 질문을 보니 사람들이 섬의 외곽 좌표만 계산하는 것을 보았다.

그게 훨씬 효율적일것이라고 생각해서 넣은 코드이다.

기준 좌표에서 상하좌우에 0(바다 값)이 있으면 한 번이라도 곱하면 0이 되기 때문에 영역 내의 상하좌우를 곱해서 최종 값이 0이면 외곽 좌표이므로 그때 v[cnt]에 넣어주었다.

(그런데 그냥 모든 좌표 모조리 넣어서 거리 계산했을 때랑 시간 똑같이 나왔다.)

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

int N, field[101][101], check[101][101];
vector<pair<int, int>> v[5001];

int xmove[4] = { 1, -1, 0, 0 }, ymove[4] = { 0,0,1,-1 };

void BFS(int cnt, int startX, int startY) {
	v[cnt].push_back(make_pair(startX, startY));
	queue<pair<int, int>> q;
	q.push(make_pair(startX, startY));
	check[startX][startY] = true;

	while (!q.empty()) {
		int tempX = q.front().first;
		int tempY = q.front().second;
		q.pop();

		for (int i = 0; i < 4; i++) {
			int x = tempX + xmove[i];
			int y = tempY + ymove[i];

			if (!check[x][y] && field[x][y]) {
				if (x >= 0 && y >= 0 && x < N && y < N) {
					q.push(make_pair(x, y));
					check[x][y] = true;
					int temp = 1;
					for (int i = 0; i < 4; i++) {
						int xX = x + xmove[i];
						int yY = y + ymove[i];
						if(xX >= 0 && yY >= 0 && xX < N && yY < N)
							temp *= field[xX][yY];
					}
					if(temp == 0)
						v[cnt].push_back(make_pair(x, y));
				}
			}
		}
	}
}

int cal(pair<int, int> & a, pair<int, int> & b) {
	return (abs(a.first - b.first) + abs(a.second - b.second))-1;
}

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

	cin >> N;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cin >> field[i][j];
		}
	}
	int count = 0;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (!check[i][j] && field[i][j]) {
				BFS(count, i, j);
				count++;
			}
		}
	}

	int m = 987654321;

	for (int i = 0; i < count; i++) {
		for (int j = i + 1; j < count; j++) {
			for (int k = 0; k < v[i].size(); k++) {
				for (int g = 0; g < v[j].size(); g++) {
					m = min(m, cal(v[i][k], v[j][g]));
				}
			}
		}
	}
	cout << m;
	return 0;
}

 처음에 OutOfBounds 런타임 에러를 받았는데 땅이 총 100 * 100 이므로 나올 수 있는 섬의 최대 개수는 5000개이다. (10000개의 영토에 한 칸씩 띄어서 있는 경우)

그래서 v[5001]를 했어야 했는데 처음에 아무 생각 없이 v[101]로 해서 틀렸다.

 

728x90
저작자표시 비영리 변경금지 (새창열림)

'문제 풀이 > 백준 알고리즘' 카테고리의 다른 글

[baekjoon 2447] 별 찍기 - 10 (재귀 호출) (C++)  (0) 2021.02.09
[baekjoon 11729] 하노이의 탑 이동 순서 (재귀 호출) (C++)  (0) 2021.02.09
[baekjoon 2110] 공유기 설치 (이진탐색) (C++)  (0) 2021.02.07
[baekjoon 11725] 트리의 부모 찾기- 트리, 그래프, BFS, DFS (C++)  (0) 2021.02.05
[baekjoon 2011] 암호코드- DP(동적 프로그래밍) (C++)  (0) 2021.02.03
    '문제 풀이/백준 알고리즘' 카테고리의 다른 글
    • [baekjoon 2447] 별 찍기 - 10 (재귀 호출) (C++)
    • [baekjoon 11729] 하노이의 탑 이동 순서 (재귀 호출) (C++)
    • [baekjoon 2110] 공유기 설치 (이진탐색) (C++)
    • [baekjoon 11725] 트리의 부모 찾기- 트리, 그래프, BFS, DFS (C++)
    dev_beomgeun
    dev_beomgeun
    백엔드 개발을 하며 얻은 지식과 경험을 공유합니다. 현재 카카오페이에서 백엔드 엔지니어로 일하고 있습니다.

    티스토리툴바