새소식

💻 Computer/🐘 Algorithm

[2146] 다리 만들기 - C++

  • -

 

2146번: 다리 만들기

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

www.acmicpc.net

1. 문제 요약

대륙간의 놓을 수 있는 다리 중 가장 짧은 다리의 길이를 알아내야 함

 


2. 전략

BFS를 써야 하는 것은 너무도 당연하다.

 

내가 생각한 방법은 정말 간단하다, 바다옆에 육지가 있는 부분에서 모두 BFS를 돌려 보는 것이다.

그런데 위의 방법에는 한 가지 문제가 있다.

 

내가 출발한 대륙에서 BFS를 돌려 다른 대륙에 도착한 건지, 아니면 빙 돌아와 내가 서 있었던 대륙에 다시 도착한 건지 알 방법이 없다. 

 

이 문제를 해결하기 위해서 나는 각 대륙마다 고유의 번호를 부여하는 방법을 선택하였다.

 


3. 주의 점

BFS를 두 번 사용한다

  1. 섬에 번호를 적을 때
  2. 짧은 다리를 찾을 때

 


4. 의사 코드

int  main(){
	int N;
    cin >> N;
	input(); //입력
	for(0~N){
    	for(0~N){
        	if(보드를 순회하다 육지(대륙)를 만난다면)
            	그 대륙에 번호를 배기는 BFS를 돌림(번호는 2부터 시작)
           	if(현재 위치(x, y)가 육지이고 && 주변에 물(0)이 하나라도 있다면)
            	대륙간의 가장 짧은 다리를 찾는 BFS를 돌림	
        }
    }
    답 출력
}

 


5. 코드

전체 코드

더보기
#include <bits/stdc++.h>

using namespace std;
void init(){
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
}

int N, board[102][102], vis[102][102], isLandCnt = 1, ans = 2'000'000'000;
int dx[4] = {1,-1,0,0}, dy[4] = {0,0,1,-1};
queue<pair<int, int>> isLandQ;

// Out of Bounds Check(배열을 나가는지 체크하는 함수)
bool OOB(int x, int y){
  return x < 0 || x >= N || y < 0 || y >= N;
}

// 다리를 찾는 BFS함수
int findBridge(int localIsland){
  while(!isLandQ.empty()){
    int x, y; tie(x, y) = isLandQ.front(); isLandQ.pop();
    for(short dir = 0; dir < 4; ++dir){
      int nx = x + dx[dir], ny = y + dy[dir];
      if(OOB(nx, ny)) continue;
      if(vis[nx][ny] >= 0 || board[nx][ny] == localIsland) continue;
      if(board[nx][ny] > 0){
        return vis[x][y];
      }
      isLandQ.push({nx, ny});
      vis[nx][ny] = vis[x][y] + 1;
    }
  }
  return 2'000'000'000;
}

// 주변에 물이 하나라도 있는지 확인하는 함수
bool findZero(int x, int y){
  for(int dir = 0; dir < 4; ++dir){
    int nx = x+dx[dir], ny = y+dy[dir];
    if(OOB(nx, ny))continue;
    if(board[nx][ny] == 0) return true;
  }
  return false;
}

// 대륙에 고유의 번호를 부여하는 함수
void numberOfIsland(){
  while(!isLandQ.empty()){
    int x, y;
    tie(x, y) = isLandQ.front(); isLandQ.pop();
    for(int dir = 0; dir < 4; ++dir){
      int nx = x + dx[dir], ny = y + dy[dir];
      if(OOB(nx, ny) || board[nx][ny] != 1) continue;
      isLandQ.push({nx, ny});
      board[nx][ny] = isLandCnt;
    }
  }
}

int main(){
  init();
  memset(vis, -1, sizeof(vis));
  cin >> N;
  for(int i =0; i < N; ++i)
    for(int j = 0; j < N; ++j)
      cin >> board[i][j];

  for(int i = 0; i < N; ++i){
    for(int j = 0; j < N; ++j){
      if(board[i][j] == 1){
        ++isLandCnt;
        isLandQ.push({i, j});
        board[i][j] = isLandCnt;
        numberOfIsland();
      }
      if(board[i][j] > 1 && findZero(i, j)){
        isLandQ.push({i,j});
        vis[i][j] = 0;
        ans = min(ans, findBridge(board[i][j]));
        memset(vis, -1, sizeof(vis));
        isLandQ = queue<pair<int, int>>();
      }
    }
  }
  cout << ans;
  return 0;
}

 

다리를 찾는 함수

// 다리를 찾는 BFS함수
int findBridge(int localIsland){
  while(!isLandQ.empty()){
    int x, y; tie(x, y) = isLandQ.front(); isLandQ.pop();
    for(short dir = 0; dir < 4; ++dir){
      int nx = x + dx[dir], ny = y + dy[dir];
      if(OOB(nx, ny)) continue;
      if(vis[nx][ny] >= 0 || board[nx][ny] == localIsland) continue;
      if(board[nx][ny] > 0){
        return vis[x][y];
      }
      isLandQ.push({nx, ny});
      vis[nx][ny] = vis[x][y] + 1;
    }
  }
  return 2'000'000'000;
}

인자로 들어오는 localIsland는 내가 출발한 대륙을 알아보기 위해 받아오는 것

 


6. 새로 알게 된 것

memset

배열을 -1이나 0으로 초기화할 때 memset을 많이 사용하곤 한다.

int vis[102][102]

위와 같은 배열이 있다면 어떻게 초기화해야 할까

1. memset(vis, -1, 102*102)
2. memset(vis, -1, sizeof(vis))
3. memset(vis, -1, sizeof(int) * 102 * 102)

답: ②, ③ 

 

크기가 바이트 단위인걸 생각 못하고 ①번 방법으로 하면서 왜 계속 틀리는 거지? 했다.

 

init queue

큐를 초기화하는 방법

queue<pair<int, int>> Q

//초기화
Q = queue<pair<int,int>>();

이런 방법도 있었다.

'💻 Computer > 🐘 Algorithm' 카테고리의 다른 글

[1600] 말이 되고픈 원숭이 - C++  (0) 2023.08.23
[1456] 거의 소수 - C++  (0) 2023.07.14
[2457] 공주님의 정원 - C++  (0) 2023.07.09
[2156] 포도주 시식 - C++  (0) 2023.07.02
[1520] 내리막 길 - C++  (0) 2023.06.30
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.