[문제]

 

www.acmicpc.net/problem/20056

 

20056번: 마법사 상어와 파이어볼

첫째 줄에 N, M, K가 주어진다. 둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다. 서로 다른 두 파이어볼의 위치

www.acmicpc.net

 

[풀이]

 

구현 문제로 k번의 이동 후 , 남아있는 파이어볼의 질량을 구하는 문제이다.

 

파이어볼이 이동하고 , 파이어볼이 2개 이상 존재하는 곳은 파이어볼이 하나로 합쳐진 뒤 4개로 나누어진다.

따라서 파이어볼이 이동하는 move 함수와, 파이어볼이 나누어지는 solve 함수를 따로 구현하였다.

 

먼저 입력받은 파이어볼의 정보를 fire라는 구조체 벡터에 저장한다.

 

move 함수에서는 fire 구조체 벡터에 저장된 파이어볼이 하나씩 움직인다.

이 때 신경써야 할 부분은 '1번 행은 N번과 연결되어 있고, 1번 열은 N번 열과 연결되어 있다.'

따라서 속력 s를 N으로 나머지 연산을 하고, 0보다 작거나 N보다 크고 같은 경우 N을 더해주거나 빼줬다.

한 공간에 2개 이상의 파이어볼이 존재한다면 나누어줘야 하므로 이차원 배열 벡터를 사용해 파이어볼의 위치를 저장했다.

 

solve 함수에서는 파이어볼이 움직이는 함수로 map의 사이즈가 2보다 크거나 같은 경우 나누어지도록 하였다.

여기서 조심해야 될 부분은 해당 좌표에 존재하는 파이어볼의 방향이 모두 짝수이거나 홀수인 경우와 그렇지 않을 경우의 방향이 달라지므로 신경써줘야 된다.

파이어볼을 나누고 파이어볼의 좌표도 달라졌으므로 map도 clear 해줘야된다. 

또한 파이어볼의 좌표, 속력, 방향, 무게가 모두 바꼈으므로 fire 구조체도 update 해줘야된다.

 

이와 같은 방법으로 K번 반복한 뒤 , 존재하는 파이어볼의 무게를 모두 더하여 출력하면 된다. 

 

[코드]

 

시간 : 16ms

 

#include <iostream>
#include <vector>

#define MAX 51

using namespace std;

struct FIRE{
    int x,y;
    int m,s,d;
};

int dx[8]={-1,-1,0,1,1,1,0,-1};
int dy[8]={0,1,1,1,0,-1,-1,-1};

int N,M,K;
vector <int> map[MAX][MAX];
vector <FIRE> fire;

void solve()
{
    vector <FIRE> tmp;

    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            int num = map[i][j].size();

            if(num >= 2){
                int m=0,s=0,d=0;
                bool odd = false;
                bool even = false;
                for(int k=0;k<num;k++){
                    int idx = map[i][j][k];
                    m += fire[idx].m;
                    s += fire[idx].s;
                    if(fire[idx].d%2 == 0)  even=true;
                    else    odd= true;
                }
                m = m/5;
                s = s/num;
                
                if(m!=0){
                    if(odd && even)  d=1;
                    else    d=0;
                    
                    for(int k=0;k<4;k++){
                        tmp.push_back({i,j,m,s,d});
                        d+=2;
                    }
                }
            }
            else if(num==1)    {
                int idx = map[i][j][0];
                tmp.push_back(fire[idx]);
            }
            map[i][j].clear();
        }
    }
    fire.clear();
    fire = tmp;
}

void move()
{
    for(int i=0;i<fire.size();i++){
                
        int x= fire[i].x;
        int y= fire[i].y;
        int s= fire[i].s;
        int d= fire[i].d;
        
        s = s%N;
        x = x+dx[d]*s;
        y = y+dy[d]*s;
        
        if(x < 0)   x+=N;
        if(x >= N) x -=N;
        
        if(y < 0)   y+=N;
        if(y >= N) y-= N;
        
        fire[i].x = x;
        fire[i].y = y;
        map[x][y].push_back(i);
    }
}

int main(void)
{
    cin >> N >> M >> K;
    
    for(int i=0;i<M;i++){
        int x,y,m,s,d;
        cin >> x >> y >> m >> s >> d;
        fire.push_back({x,y,m,s,d});
    }
    
    for(int i=0;i<K;i++){
        move();
        solve();
    }
    
    int ans=0;
    for(int i=0;i<fire.size();i++)  ans += fire[i].m;
    
    cout << ans;
    return 0;
}

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

[백준] 4179번. 불!  (0) 2021.01.08
[백준] 1018번. 체스판 다시 칠하기  (0) 2021.01.08
[백준] 15653번. 구슬 탈출4  (0) 2021.01.07
[백준] 2931번. 가스관  (0) 2021.01.05
[백준]1756번. 피자 굽기  (0) 2021.01.04

[문제]

 

www.acmicpc.net/problem/15653

 

15653번: 구슬 탈출 4

첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B'

www.acmicpc.net

 

[풀이]

 

처음에는 DFS 방식으로 접근을 하였다.

하지만 생각을 해보니 DFS 함수의 탈출 조건을 설정할 수 없었다.

 

따라서 다른 방법을 생각하던 중 BFS 방식으로 풀어야겠다고 생각했다.

BFS 방식에서 처음 입력 값의 빨간, 파란 공의 위치를 시작으로 상,하,좌,우 방향으로 움직이도록 하였다.

이 때 파란 공이 골에 들어가거나, 이미 방문했던 위치라면 continue를 사용해 queue에 push하지 못하도록 하였다.

 

또한 움직인 빨간 공이 골에 들어갔다면 cnt를 return 하면서 BFS 함수를 끝내도록 하였다.

이러한 방식으로  queue가 empty가 아닐 때까지 반복하도록 하였다.

 

 

 

[코드]

 

시간 : 0ms

 

#include <iostream>
#include <queue>

#define MAX 11

using namespace std;

struct pos{
    int x,y;
};

struct ball{
    int rx,ry;
    int bx,by;
    int cnt;
};

pos red,blue,goal;

int map[MAX][MAX]={0,};
int N,M;
bool visited[MAX][MAX][MAX][MAX]={false,};

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};


pos move(int x, int y,int dir)
{

    while(1){
        x+=dx[dir];
        y+=dy[dir];
        if(x < 0 || y <0 || x >= N || y >= M || map[x][y] != 0 ){
            x -= dx[dir];
            y -= dy[dir];
            break;
        }
        if(goal.x==x && goal.y== y) break;
    }

    return {x,y};
}

int BFS()
{
    queue <ball> q;
    
    q.push({red.x,red.y,blue.x,blue.y,0});
    visited[red.x][red.y][blue.x][blue.y]=true;
    
    while(!q.empty()){

        int rx = q.front().rx;   int ry= q.front().ry;
        int bx = q.front().bx;   int by= q.front().by;
        int cnt = q.front().cnt;
        q.pop();
        
        for(int i=0;i<4;i++){
            
            pos tmp_red = move(rx,ry,i);
            pos tmp_blue = move(bx,by,i);
            
            
            if((tmp_blue.x == goal.x) &&(tmp_blue.y==goal.y))  continue;
            if((tmp_red.x==goal.x)&&(tmp_red.y == goal.y))    return cnt+1;
            
            if((tmp_blue.x==tmp_red.x)&&(tmp_blue.y==tmp_red.y)){
                
                if(i==0){
                    if(rx < bx)  tmp_blue.x++;
                    else    tmp_red.x++;
                }
                else if(i == 1){
                    if(ry < by)  tmp_red.y--;
                    else    tmp_blue.y--;
                }
                else if(i == 2){
                    if (rx < bx) tmp_red.x--;
                    else    tmp_blue.x--;
                }
                else if(i == 3){
                    if( ry< by) tmp_blue.y++;
                    else    tmp_red.y++;
                }
            }
            
            if(visited[tmp_red.x][tmp_red.y][tmp_blue.x][tmp_blue.y])   continue;
            visited[tmp_red.x][tmp_red.y][tmp_blue.x][tmp_blue.y]=true;
            q.push({tmp_red.x,tmp_red.y,tmp_blue.x,tmp_blue.y,cnt+1});
        }
    }
    return -1;
}

int main(void)
{
    cin >> N >> M;
    
    for(int i=0;i<N;i++){
        for(int j=0;j<M;j++){
            
            char ch;
            cin >> ch;
            if(ch=='#') map[i][j]=-1;
            else if(ch=='O')    goal={i,j};
            else if(ch=='R')    red = {i,j};
            else if(ch=='B')    blue = {i,j};
        }
    }
    
    cout << BFS();
    
    return 0;
    
}

[문제]

 

www.acmicpc.net/problem/2931

 

2931번: 가스관

러시아 가스를 크로아티아로 운반하기 위해 자그레브와 모스코바는 파이프라인을 디자인하고 있다. 두 사람은 실제 디자인을 하기 전에 파이프 매니아 게임을 이용해서 설계를 해보려고 한다.

www.acmicpc.net

 

[풀이]

 

맞아서 기분이 좋긴 하지만 뭔가 찝찝하다.

3 5
. . . . .
. M . Z .
. . . . .

 

위와 같은 예제는 답이 제대로 나오지 않는다.

 

시작점을 기준으로 DFS 함수를 통해 한칸씩 나아가도록 하였다.

이 때 현재 위치의 값이 '.' 이라면 solve 함수에서 해당 위치에 들어갈 값을 찾도록 하였다.

 

 

[코드]

 

시간 : 0ms

 

#include <iostream>
#define MAX 26

using namespace std;

struct pos {
    int x,y;
};

char map[MAX][MAX]={0,};

int R,C;

int dx[4] ={-1,0,1,0};
int dy[4] ={0,1,0,-1};

pos start;

void solve(int x, int y)
{
    cout << x+1 << " " << y+1 << " ";
    bool dir[4] = {0,};
    
    for(int i=0;i<4;i++){
        
        int nx = x+dx[i];
        int ny = y+dy[i];
        
        if(nx<0 || ny< 0 || nx >= R || ny >= C )   continue;
        
        if(map[nx][ny] != '.'){
            if(i == 0 && (map[nx][ny] == '1' || map[nx][ny] == '4' || map[nx][ny] == '|' || map[nx][ny] =='+'))  dir[i]=true;
            else if(i == 1 && (map[nx][ny] == '3' || map[nx][ny] == '4' || map[nx][ny] == '-' || map[nx][ny] =='+'))  dir[i]=true;
            else if(i == 2 && (map[nx][ny] == '2' || map[nx][ny] == '3' || map[nx][ny] == '|' || map[nx][ny] =='+'))  dir[i]=true;
            else if(i == 3 && (map[nx][ny] == '1' || map[nx][ny] == '2' || map[nx][ny] == '-' || map[nx][ny] =='+'))  dir[i]=true;

        }
    }
    if(dir[0] && dir[1] && dir[2] && dir[3])    cout << "+";
    else if(dir[1] && dir[2])   cout << "1";
    else if(dir[0] && dir[1])   cout << "2";
    else if(dir[0] && dir[3])   cout << "3";
    else if(dir[2] && dir[3])   cout << "4";
    else if(dir[0] && dir[2])   cout << "|";
    else if(dir[1] && dir[3])   cout << "-";
    
    return ;
}

void DFS(int x, int y, int dir)
{
    if(map[x][y] == '.'){
        solve(x,y);
        return ;
    }
    
    int nx = x+dx[dir];
    int ny = y+dy[dir];
    
    if(dir ==0 ){
        if(map[nx][ny] == '|' || map[nx][ny] == '+')    dir = 0;
        else if(map[nx][ny] =='1')    dir= 1;
        else if(map[nx][ny] =='4') dir = 3;
    }
    else if(dir == 1 ){
        if(map[nx][ny] == '-' || map[nx][ny] == '+')    dir = 1;
        else if(map[nx][ny] =='3')    dir= 0;
        else if(map[nx][ny] =='4') dir = 2;
    }
    else if(dir == 2){
        if(map[nx][ny] == '|' || map[nx][ny] == '+')    dir = 2;
        else if(map[nx][ny] =='2')    dir= 1;
        else if(map[nx][ny] =='3') dir = 3;
    }
    else if(dir == 3){
        if(map[nx][ny] == '-' || map[nx][ny] == '+')    dir = 3;
        else if(map[nx][ny] =='1')    dir= 2;
        else if(map[nx][ny] =='2') dir = 0;
    }
    DFS(nx,ny,dir);
    return;
}

int main(void)
{

    cin >> R>>C;
    for (int i=0; i<R; i++){
        for(int j=0;j<C;j++){
            cin >> map[i][j];
            if(map[i][j]== 'M')  start = {i,j};
        }
    }
    
    int Direction =0;
    
    for (int i = 0; i < 4; i++) {
        int nx =start.x + dx[i];
        int ny =start.y + dy[i];

        if (nx < 0 || nx >= R || ny < 0 || ny >= C) continue;
        if (map[nx][ny] != '.') {
            if (nx ==start.x) {
                if (ny == start.y - 1)  Direction = 3;
                else if (ny == start.y+ 1)  Direction = 1;
            }
            else if (ny == start.y) {
                if (nx == start.x - 1)  Direction = 0;
                else if (nx ==start.x + 1)  Direction = 2;
            }
        }
    }

    DFS(start.x,start.y,Direction);
    return 0;
}

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

[백준]20056번. 마법사 상어와 파이어볼  (2) 2021.01.07
[백준] 15653번. 구슬 탈출4  (0) 2021.01.07
[백준]1756번. 피자 굽기  (0) 2021.01.04
[백준] 13913번. 숨바꼭질4  (0) 2021.01.03
[백준] 2589. 보물섬  (0) 2021.01.01

[문제]

 

www.acmicpc.net/problem/1756

 

1756번: 피자 굽기

월드피자 원주 지점에서 N개의 피자 반죽을 오븐에 넣고 구우려고 한다. 그런데, 월드피자에서 만드는 피자 반죽은 지름이 제각각이다. 그런가하면, 월드피자에서 사용하는 오븐의 모양도 몹시

www.acmicpc.net

[풀이]

 

오븐의 지름, 피자 반죽의 지름이 주어지고 마지막 피자 반죽의 위치를 출력하면 된다.

 

처음에는 완전 탐색으로 풀까 생각했는데 N,D의 최댓 값이 300,00이라서 시간초과가 나오게 된다.

따라서  dp 방법을 사용해 구현했다.

 

depth 라는 배열에 해당 깊이에 구워질 수 있는 피자 지름의 최댓값을 저장했다.

문제 예제로 보면 

 

7 3

5 6 4 3 6 2 3

3 2 5

 

depth 배열의 값은 5 5 4 3 3 2 2 가 된다.

 

이제 오븐의 뒤에서부터 피자를 구울 수 있는 곳을 찾아가면 된다.

 

3 2 5 로 보면 지름이 3인 피자는 뒤에서 3번째의 위치에서 ( 5 5 4 3 3 2 2 ) 구울 수 있다. 

그 다음으로 지름이 2인 피자는 뒤에서 3번째보다 더 앞 부분에서 구워야 하므로 

뒤에서 4번째 위치에서 ( 5 5 4 3 3 2 2 )  구울 수 있다.

마지막으로 지름이 5인 피자는 앞에서 2번째의 위치에서 ( 5 5 4 3 3 2 2 ) 구울 수 있다.

 

이런식으로 모든 피자에 대해 반복하고 오븐의 마지막 위치를 출력하면 된다.

 

 

[코드]

 

시간 : 264ms

 

#include <iostream>
#include <vector>

#define MAX 300001

using namespace std;

int D,N;
int depth[MAX]={0,};
int pizza[MAX]={0,};

int main(void)
{
    cin >> D >> N;
    for(int i=0;i<D;i++){
        cin >> depth[i];
        if( i>0 &&  depth[i-1] < depth[i])   depth[i] = depth[i-1];
    }
    
    for(int i=0;i<N;i++)    cin >> pizza[i];
    
    int idx = 0;
    for(int i=D-1 ; i>=0; i--){
        if(depth[i] >= pizza[idx])  idx++;
        if(idx==N){
            cout << i+1;
            break;
        }
        if(i==0){
            cout <<"0";
            break;
        }
    }
    return 0;
    
}

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

[백준] 15653번. 구슬 탈출4  (0) 2021.01.07
[백준] 2931번. 가스관  (0) 2021.01.05
[백준] 13913번. 숨바꼭질4  (0) 2021.01.03
[백준] 2589. 보물섬  (0) 2021.01.01
[백준] 5427번. 불  (0) 2020.12.31

[문제]

 

www.acmicpc.net/problem/13913

 

13913번: 숨바꼭질 4

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

 

[풀이]

 

수빈이의 위치 N, 동생의 위치 K가 입력으로 주어지고 수빈이가 동생을 찾는 최단경로를 구하는 문제.

이 때, 수빈이는 현재 위치 X 에서 X-1,X+1,2*X로만 움직일 수 있다.

 

최단경로를 찾아야 하므로 BFS를 사용했다.

현재 위치 X에서  X-1,X+1,2*X로 움직이도록 하였고 visited 배열을 사용해 재방문 하지 않도록 했다.

또한 경로도 구해야 parent 배열을 사용해 해당 index에 오기 전 index 값을 저장했다.

 

처음의 input의 범위가 0부터 100,000 사이라서 MAX 값을 100,001로 설정하였는데

5001 100000과 같은 경우 

 

최단 경로를 구하기 위해 100,000을 넘어가는 경우도 있으므로 MAX 값을 200,001로 변경하였다.

 

 

[코드]

 

시간 : 20 ms

 

#include <iostream>
#include <queue>
#define MAX 200001

using namespace std;

int n[2] = {-1,1};
int visited[MAX]={0,};
int parent[MAX]={0,};
int N,K;
vector <int> ans;

void bfs()
{
    queue<int> q;
    q.push(N);
    
        int idx = q.front();
        q.pop();
        
        if(idx == K ){
            cout << visited[idx] << "\n";
            while(idx != N){
                ans.push_back(idx);
                idx= parent[idx];
            }
            ans.push_back(N);
            return ;
        }
        for(int i=0;i<3;i++){
            int nidx =0;
            if(i==2)    nidx = idx*2;
            else nidx = idx+n[i];
            
            if(nidx < 0 || nidx > MAX || visited[nidx] ) continue;
            
            q.push(nidx);
            visited[nidx]=visited[idx]+1;
            parent[nidx] = idx;
        }
    }

int main(void)
{
    cin >> N >> K;
    bfs();
    int _size = ans.size()-1;
    for(int i=_size; i>=0 ; i--)
        cout << ans[i]<< " ";
    return 0;
}

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

[백준] 2931번. 가스관  (0) 2021.01.05
[백준]1756번. 피자 굽기  (0) 2021.01.04
[백준] 2589. 보물섬  (0) 2021.01.01
[백준] 5427번. 불  (0) 2020.12.31
[백준] 2146번. 다리 만들기  (0) 2020.12.30

[문제]

 

www.acmicpc.net/problem/2589

 

2589번: 보물섬

보물섬 지도를 발견한 후크 선장은 보물을 찾아나섰다. 보물섬 지도는 아래 그림과 같이 직사각형 모양이며 여러 칸으로 나뉘어져 있다. 각 칸은 육지(L)나 바다(W)로 표시되어 있다. 이 지도에서

www.acmicpc.net

[풀이]

 

 두 보물간의 최단거리를 구하는 문제.

최단거리를 구하는 문제이길래 BFS를 사용해서 풀려고 했다.

 

하지만 보물의 위치가 어딘지 몰라서 시작점과 도착점을 설정하는 데 있어 어려움을 겪었다.

 

생각해보니 map의 최대 사이즈는 50*50이라서 모든 육지에 대해서 시작점으로 잡고 최단거리를 구해도 되겠다고 생각을 하였다.

 

따라서 모든 육지에 대해 출발점으로 잡고 BFS 함수에서 최단거리를 구해 그 중에서도 가장 먼 거리를 정답으로 하도록 구현하였다. 

 

 

[코드]

 

시간 : 140ms

 

#include <iostream>
#include <queue>
#include <cstring>

#define MAX 51

using namespace std;

struct pos{
    int x,y;
};
int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

bool map[MAX][MAX]={0,};
int visited[MAX][MAX]={0,};
int N,M;

int BFS(int x,int y)
{
    memset(visited,0,sizeof(visited));
    
    queue <pos> q;
    q.push({x,y});
    visited[x][y]=1;
    int res =0;
    
    while(!q.empty()){
    
        int x= q.front().x;
        int y= q.front().y;
        
        if(res < visited[x][y]) res= visited[x][y];
        
        q.pop();
        
        for(int i=0;i<4;i++){
            int nx = x+dx[i];
            int ny = y+dy[i];
            
            if(nx < 0 || ny < 0 || nx >= N || ny >= M || visited[nx][ny]!=0 || map[nx][ny] )  continue;
            
            q.push({nx,ny});
            visited[nx][ny]=visited[x][y]+1;
            
        }
    }
    
    return res;
}

int main(void){
    
    cin >> N >> M;
    
    for(int i=0;i<N;i++){
        for(int j=0;j<M;j++){
            char ch;
            cin >> ch;
            if(ch == 'W')   map[i][j]=true;
        }
    }
    
    int ans =0;
    for(int i=0;i<N;i++){
        for(int j=0;j<M;j++){
            if(map[i][j]==0){
                int res = BFS(i,j);
                if(res > ans )  ans = res;
            }
        }
    }
    cout << ans-1;
    return 0;
}

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

[백준]1756번. 피자 굽기  (0) 2021.01.04
[백준] 13913번. 숨바꼭질4  (0) 2021.01.03
[백준] 5427번. 불  (0) 2020.12.31
[백준] 2146번. 다리 만들기  (0) 2020.12.30
[백준] 1937번. 욕심쟁이 판다  (0) 2020.12.28

[문제]

 

www.acmicpc.net/problem/5427

 

5427번: 불

상근이는 빈 공간과 벽으로 이루어진 건물에 갇혀있다. 건물의 일부에는 불이 났고, 상근이는 출구를 향해 뛰고 있다. 매 초마다, 불은 동서남북 방향으로 인접한 빈 공간으로 퍼져나간다. 벽에

www.acmicpc.net

[풀이]

 

매 초마다 불은 상,하,좌,우 방향으로 퍼져 나간다.

이 때 상근이가 탈출하는데 걸리는 시간을 구하는 문제이다.

 

처음에는 불이 퍼지는 함수랑 상근이가 움직이는 함수를 따로 만들어서 풀었다.

DFS를 사용해 상근이가 움직이도록 했는데, DFS로 움직일 때마다 map을 저장하기 위해 배열을 하나 더 지역변수로 선언했다.

하지만 map의 크기가 워낙 커서 계속 오류가 났다.

 

두번째 방법으로 BFS 함수에서 불이 퍼지는 것과 상근이가 움직이는 것을 모두 구현했다.

 

처음에는 불이 퍼지는 것을 그냥 반복문으로 돌면서 불을 만나면 상,하,좌,우로  퍼지도록 구현했다.

하지만 시간초과가 나와서 불이 퍼지는 것도 BFS로 queue를 사용해 풀었다.  

 

불이 퍼지고 상근이가 움직이는 것을 구현하기 위해  queue의 size만큼 while문을 반복하도록 구현하였다. 

 

 

[코드]

 

시간 : 176ms

 

#include <iostream>
#include <cstring>
#include <queue>

#define MAX 1001

using namespace std;

struct pos{
    int x,y;
};

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};

pos start;
int visited[MAX][MAX]={0,};
int map[MAX][MAX]={0,};
int w,h;
int res=0;

queue <pos> fq;

void BFS()
{
    queue <pos> q;
    
    q.push(start);
    visited[start.x][start.y]=1;
    
    while(!q.empty()){
        
        int _size = q.size();
        int fsize = fq.size();
        
        while(fsize--){
            int x = fq.front().x;
            int y = fq.front().y;
            
            fq.pop();
            
            for(int i=0;i<4;i++){
                
                int nx = x+dx[i];
                int ny = y+dy[i];
                
                if(nx<0 || ny<0 || nx>=w || ny >= h || map[nx][ny]!= 0 || visited[nx][ny] != 0)  continue;

                map[nx][ny]=1;
                visited[nx][ny]=-1;
                fq.push({nx,ny});
            }
        }
        
        while(_size--){
        
            int x = q.front().x;
            int y = q.front().y;
            
            q.pop();
            
            for(int i=0;i<4;i++){
                
                int nx = x+dx[i];
                int ny = y+dy[i];
                
                if(nx<0 || ny<0 || nx>=w || ny >= h){
                    res = visited[x][y];
                    return;
                }
                
                if(map[nx][ny]!= 0 || visited[nx][ny]!=0)  continue;

                visited[nx][ny]=visited[x][y]+1;
                q.push({nx,ny});
                            
            }
        }
    }
}


int main(void)
{
    int T;
    cin >> T;
    
    for(int k=0;k<T;k++)
    {
        memset(visited, false, sizeof(visited));
        memset(map, false, sizeof(map));

        while(!fq.empty())  fq.pop();
        
        cin >> h >> w;
        res=0;
        
        for(int i=0;i<w;i++){
            for(int j=0;j<h;j++){
                
                char ch;
                cin >> ch;
                
                if( ch == '@')  start={i,j};
                else if( ch == '*') {
                    map[i][j]=1;
                    visited[i][j]=-1;
                    fq.push({i,j});
                }
                else if( ch == '#') map[i][j]=1;
                
            }
        }
        
        BFS();
        
        if(res==0)  cout << "IMPOSSIBLE";
        else    cout << res;
        
        cout << "\n";
    }
    
    return 0;
}

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

[백준] 13913번. 숨바꼭질4  (0) 2021.01.03
[백준] 2589. 보물섬  (0) 2021.01.01
[백준] 2146번. 다리 만들기  (0) 2020.12.30
[백준] 1937번. 욕심쟁이 판다  (0) 2020.12.28
[백준] 13459. 구슬 탈출  (0) 2020.12.21

[문제]

 

www.acmicpc.net/problem/2146

 

2146번: 다리 만들기

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

www.acmicpc.net

[풀이]

 

섬을 연결하는 다리를 설치할 수 있는데, 가장 짧은 다리 하나를 설치할 수 있다.

이 때 가장 짧은 다리의 길이를 구하는 문제.

 

처음에는 섬을 분리하여, 섬의 가장자리에서 다른 섬의 가장자리로의 최단 거리를 구하려고 했다.

생각해보니 가장자리를 따로 구하지 않고 ,

BFS를 통해 최단 거리를 구하면 하나의 섬의 가장자리에서 다른 섬의 가장자리까지의 거리가 된다. 

 

따라서 DFS 함수에서 각 섬을 구분하고, BFS 함수에서 섬 간의 최단거리를 구했다.

BFS에서 최단거리를 구할 때 시작섬의 좌표를 queue에 모두 넣어줬다.

그리고 하나씩 pop하여 상,하,좌,우 방향으로 퍼져나갔다.

이 때 다른 섬을 만나면 거리를 return 하면서 BFS 함수를 종료하였다. 

 

이와 같은 방식으로 첫번째 섬부터 마지막 섬까지 반복하여  가장 짧은 다리의 길이를 구할 수 있다. 

 

[코드]

 

시간 : 44ms

 

#include <iostream>
#include <queue>
#define MAX 101

using namespace std;

struct pos{
    int x,y;
};

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};
int map[MAX][MAX]={0,};
bool tmp[MAX][MAX]={0,};
int N;
int cnt=0;
int answer=MAX*MAX;

void DFS(int x, int y,int cnt)
{
    map[x][y]=cnt;
    tmp[x][y]=true;
    
    for(int i=0;i<4;i++){
        int nx = x+dx[i];
        int ny = y+dy[i];
        if(nx<0 || ny <0 || nx >= N || ny >= N || tmp[nx][ny] || map[nx][ny]==0 )  continue;
        
        DFS(nx,ny,cnt);
    }
}

int BFS(int idx)
{
    int visited[MAX][MAX]={0,};
    queue <pos> q;
    
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(map[i][j]==idx){
                q.push({i,j});
                visited[i][j]=1;
            }
        }
    }
    
    while(!q.empty()){
        int x = q.front().x;
        int y = q.front().y;
        q.pop();

        for(int k=0;k<4;k++){
            int nx = x+dx[k];
            int ny = y+dy[k];
            
            if(nx<0 || ny <0 || nx >= N || ny >= N || visited[nx][ny]!=0 )  continue;
            if(map[nx][ny] !=0 &&  map[nx][ny] != idx)  return visited[x][y]+1;
            
            visited[nx][ny]=visited[x][y]+1;
            q.push({nx,ny});
        }
    }
    return 0;
}


int main(void)
{
    cin >> N;
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            cin >> map[i][j];
        }
    }
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(map[i][j]==1 && !tmp[i][j]){
                cnt++;
                DFS(i,j,cnt);
            }
        }
    }
    
    for(int i=1;i<cnt;i++)  {
        int res =BFS(i);
        if(res!=0 && res < answer)  answer =res;
    }
    cout << answer-2;
    return 0;
}

 

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

[백준] 2589. 보물섬  (0) 2021.01.01
[백준] 5427번. 불  (0) 2020.12.31
[백준] 1937번. 욕심쟁이 판다  (0) 2020.12.28
[백준] 13459. 구슬 탈출  (0) 2020.12.21
[백준] 1744번. 수 묶기  (0) 2020.12.16

+ Recent posts