[문제]

 

www.acmicpc.net/problem/3055

 

3055번: 탈출

사악한 암흑의 군주 이민혁은 드디어 마법 구슬을 손에 넣었고, 그 능력을 실험해보기 위해 근처의 티떱숲에 홍수를 일으키려고 한다. 이 숲에는 고슴도치가 한 마리 살고 있다. 고슴도치는 제

www.acmicpc.net

[풀이]

 

고슴도치가 비버의 굴로 이동해야 하는데 물이 있거나 돌이 있는 곳으로는 움직일 수 없다.

물은 매 분마다 인접한 곳으로 퍼진다. 단 , 비버가 존재하는 곳이나 돌이 존재하는 곳으로는 퍼질 수 없다.

이 때 최단 거리를 구하는 문제.

 

고슴도치의 이동경로를 저장하는 visited 배열과 물, 돌의 정보를 저장하는 map을 선언했다.

BFS 함수의 while 문에서 물이 먼저 퍼지고 그 다음에 고슴도치가 움직이도록 하였다.

물은 move 함수를 통해서 퍼지고 물이 있는 곳의 좌표를 vector water에 저장하였다.

 

다음으로 BFS를 사용해 고슴도치가 비버의 굴로 가는데 최단 거리를 구했다.

고슴도치가 이미 방문한 곳이라면 최단 거리를 구하는 문제이므로 continue를 걸어줬다.

또한 이미 물이 차있거나 돌이 존재하는 곳이라면 지나가지 못하므로 마찬가지로 continue를 걸어줬다.

 

이렇게 BFS를 사용해 고슴도치의 최단거리를 구할 수 있었다.

또한 BFS 함수가 끝나고 visited 배열에서 도착 지점 좌표의 값이 0이라면 고슴도치가 갈 수 없는 경우이므로 'KAKTUS'를 출력하도록 했다.

 

 

 

[코드]

 

시간 : 0ms

 

#include <iostream>
#include <queue>
#include <vector>

#define MAX 51

using namespace std;

struct pos{
    int x,y;
};

pos S,D; // 고슴도치, 비버

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

int visited[MAX][MAX]={0,};
int map[MAX][MAX]={0,};
int R,C;


vector <pos> water;

void move()
{
    int size = water.size();
    
    for(int i=0;i<size;i++)
    {
        int x= water[i].x;
        int y= water[i].y;
        
        for(int j=0;j<4;j++){
            int nx=x+dx[j];
            int ny=y+dy[j];
            
            if(nx < 0 || ny<0 || nx >= R || ny >= C || map[nx][ny] != 0) continue;
            else if( nx == D.x && ny == D.y)  continue;

            map[nx][ny]=1;
            water.push_back({nx,ny});
            
        }
    }
}

void BFS()
{
    queue <pos> q;
    q.push({S.x,S.y});
    int cnt =-1;
    
    while(!q.empty()){

        int x = q.front().x;
        int y = q.front().y;
        q.pop();
        
        if(cnt != visited[x][y]){
            move();
            cnt= visited[x][y];
         }
        if( x == D.x && y == D.y)  return;
            
        
        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 || visited[nx][ny] != 0) continue;
            else if(map[nx][ny] != 0)   continue;
            
            q.push({nx,ny});
            visited[nx][ny] = visited[x][y]+1;
            
        }
    }

}

int main(void)
{
    cin >> R >> C;
    
    for(int i=0;i<R;i++){
        for(int j=0;j<C;j++){
            char ch1;
            cin >> ch1;
            
            if(ch1 == '.')  map[i][j]=0;
            else if(ch1 == '*'){
                map[i][j]=1; //물
                water.push_back({i,j});
            }
            else if (ch1 == 'X')    map[i][j]=-1; // 돌
            else if(ch1 == 'S') S={i,j};
            else if(ch1 == 'D') D={i,j};
            
        }
    }
    
    BFS();
    if(visited[D.x][D.y] == 0)    cout<<"KAKTUS";
    else cout << visited[D.x][D.y];
    
    return 0;
    
}

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

[백준]14719. 빗물  (0) 2020.12.13
[백준] 10844. 쉬운 계단 수  (0) 2020.12.07
[백준] 2178. 미로탐색  (0) 2020.11.30
[백준] 2066. 바이러스  (0) 2020.11.30
[백준] 2206. 벽 부수고 이동하기  (0) 2020.10.30

[문제]

 

www.acmicpc.net/problem/2178

 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

 

[풀이]

 

미로의 정보가 입력으로 주어지고 시작점 (1,1)에서 도착점(N,M)까지의 최단거리를 구하는 문제이다.

1은 이동할 수 있는 칸을 의미하고, 0은 이동할 수 없는 칸을 의미한다. 

 

BFS를 사용해 풀었다. 다음 위치의 값이 1인 경우에만 좌표를 queue에 저장하였고, 이미 방문했던 곳이라면 queue에 담지 않았다.

실수했던 부분이 BFS는 동시에 움직이므로 최단거리를 구하는 경우 재방문 하지 않아도 된다.

 

[코드]

 

시간 : 0ms

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

using namespace std;

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

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

struct pos{
    int x,y;
};

int BFS()
{
    queue <pos> q;
    
    q.push({0,0});
    visited[0][0]=1;
    
    while(!q.empty()){
        
        int x= q.front().x;
        int y= q.front().y;
        if(x==N-1 && y==M-1)    break;
        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 || map[nx][ny]==0)    continue;
            if(visited[nx][ny]!= 0 )   continue;
            
            visited[nx][ny] = visited[x][y]+1;
            q.push({nx,ny});
        }
    }
    
    return visited[N-1][M-1];
}

int main(void)
{
    cin >> N >> M;
    
    for(int i=0;i<N;i++){
        for(int j=0;j<M;j++){
            scanf("%1d",&map[i][j]);
        }
    }
    
    cout << BFS();
    
    return 0;
    
}

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

[백준] 10844. 쉬운 계단 수  (0) 2020.12.07
[백준] 3055. 탈출  (0) 2020.12.03
[백준] 2066. 바이러스  (0) 2020.11.30
[백준] 2206. 벽 부수고 이동하기  (0) 2020.10.30
[백준]2193. 이친수  (0) 2020.10.29

[문제]

 

www.acmicpc.net/problem/2606

 

2606번: 바이러스

첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수가 주어

www.acmicpc.net

 

[풀이]

 

1번 컴퓨터가 바이러스에 걸렸고 1번 컴퓨터와 연결된 컴퓨터는 모두 바이러스에 걸리게 된다.

이 때 1번은 제외하고 바이러스에 걸린 컴퓨터의 갯수를 출력하면 된다.

 

문제는 DFS를 사용해서 풀 수 있었다. map이라는 2차원 배열을 선언하여 연결 정보를 저장했다.

그 다음 DFS를 1번부터 시작하여 start와 연결된 모든 컴퓨터에 대해 DFS 함수를 호출한다.

visited를 통해서 이미 방문했는지 확인하고 , 방문하지 않은 경우에만 DFS 함수를 호출하였다.

 

이렇게 DFS 함수를 끝내고 visited가 1인 컴퓨터의 개수를 count하여 출력해주면 된다.

 

 

[코드]

 

시간 : 0ms

#include <iostream>
#define MAX 101
using namespace std;

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

void DFS(int start)
{
    visited[start]=1;
    for(int i=2;i<=N;i++){
        if(map[start][i]==1 && visited[i]==0)  DFS(i);
    }
}

int main(void)
{
    int ans=0;
    
    cin >> N >> M;
    
    for(int i=0;i<M;i++){
        int a,b;
        cin >> a >> b;
        
        map[a][b]=1;
        map[b][a]=1;
        
    }
    
    DFS(1);
    for(int i=2;i<=N;i++){
        if(visited[i]==1)   ans++;
    }
    cout << ans;
    
    return 0;
    
}

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

[백준] 3055. 탈출  (0) 2020.12.03
[백준] 2178. 미로탐색  (0) 2020.11.30
[백준] 2206. 벽 부수고 이동하기  (0) 2020.10.30
[백준]2193. 이친수  (0) 2020.10.29
[백준]2096.내려가기  (0) 2020.10.29

[문제]

programmers.co.kr/learn/courses/30/lessons/42839

 

코딩테스트 연습 - 소수 찾기

한자리 숫자가 적힌 종이 조각이 흩어져있습니다. 흩어진 종이 조각을 붙여 소수를 몇 개 만들 수 있는지 알아내려 합니다. 각 종이 조각에 적힌 숫자가 적힌 문자열 numbers가 주어졌을 때, 종이

programmers.co.kr

 

[풀이]

 

에라토스테네스의 체 , next_permutation, set를 모두 공부할 수 있는 문제

 

에라토스테네스의 체는 어떤 수가 소수인지 아닌지 판별할 때 사용된다. 

 

1. 소수를 판별할 만큼 배열을 할당하고 배열을 자기 자신으로 초기화한다.

2. 2부터 자기 자신에 해당하는 것을 제외하고 배수들은 모두 0으로 바꿔서 소수에서 제외시킨다. 

 

#define MAX 10000

int arr[MAX]={0,};

void Eratos(int num)
{
    for(int i=1;i<=num;i++)
        arr[i] = i;
    
    for(int i=2 ; i<=num;i++){
        for(int j=2*i;j<=num;j+=i ){
            arr[i]=0;
        }
    }
    
    for(int i=2;i<=num;i++){
        if(arr[i]!=0)
            printf("%d",i);
    }
}

 

 

 next_permutation은 헤더에 algorithm을 추가하면 사용할 수 있는 STL이다.

벡터나 배열로 사용이 가능하며 가능한 모든 조합을 구할 수 있다.

단, 사용하기 전에 벡터나 배열이 오름차순으로 정렬되어 있어야 된다.

 

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main(void)
{
    vector <int> v;
    
    for(int i=5;i>=2;i--)   v.push_back(i);
    sort(v.begin(),v.end());
    do{
        for(int i=0;i<v.size();i++) cout << v[i];
        cout << endl;
    }while(next_permutation(v.begin(), v.end()));
    
    return  0;
}

아래 사진과 같이 벡터의 모든 조합을 구할 수 있다.

 

 

set은 중복이 허용되지 않고 자동으로 오름차순 정렬이 된다.

 

 

 

======================================================

 

문제 풀이

 

1. input으로 주어진 numbers를 내림차순으로 정렬하여 number로 만들 수 있는 숫자 중에서 가장 큰 수를 구한다.

2. 에라토스테네스의 체를 사용해 가장 큰 수 까지 소수인지 아닌지를 판별

3. 다시 numbers를 오름차순으로 정렬하여 next_permutation을 사용해 가능한 모든 조합을 구한다.

이 때 해당 숫자가 소수이고 set에 존재하지 않는다면  set에 insert

 

[코드]

 

#include <string>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

vector <int> v;
int IsPrime[10000000]={0,};
int cnt=0;

bool comp(int a, int b)
{
    if(a > b )  return true;
    return false;
}

void Eratos(int num)
{
    IsPrime[0] = 0;
    IsPrime[1] = 0;
    
    for(int i=2 ; i <= num ; i++)
    {
        IsPrime[i] = i;
    }
    
    for(int i=2;i<=num;i++)
    {
        if(IsPrime[i] == 0) continue;
        
        for(int j=2*i ; j<=num; j+=i){
            IsPrime[j]=0;
        }
    }
}

int solution(string numbers) {
    int answer = 0;
    set <int> s;
    
    sort(numbers.begin(), numbers.end(),comp);
    int num = stoi(numbers);

    Eratos(num);
    
    sort(numbers.begin(), numbers.end());
    
    do{
        for(int i=1;i<=numbers.size();i++)
        {
            string tmp1 = numbers.substr(0,i);
            num = stoi(tmp1);
            
            if(IsPrime[num]!= 0 )    s.insert(num);
        }
    }while(next_permutation(numbers.begin(),numbers.end()));

    return s.size();
}

[문제]

programmers.co.kr/learn/courses/30/lessons/42883

 

코딩테스트 연습 - 큰 수 만들기

 

programmers.co.kr

 

 

[풀이]

input으로 숫자 number와 number에서 제외할 숫자의 개수인 k가 주어진다.

number에서 k개의 숫자를 제거하여 만들 수 있는 최댓 값을 구하면 된다.

 

처음에는 DFS를 사용하여 모든 경우에 대해 다 확인해봤는데 생각해보니 number의 길이가 1부터 1,000,000까지이다.

 

그래서 다른 방법을 생각해보니 number의 시작부터 큰 수를 골라 총 number.size()-k의 숫자를 골라서 answer로 return 하면 된다. 

 

1. number의 처음부터 'k+선택된 숫자의 수'까지 중에서 가장 큰 수를 선택한다.

2. 선택한 수의 다음 index부터 'k+선택된 숫자의 수'까지 중에서 가장 큰 수를 선택한다.

위의 과정을 'number.size() - k' 번 반복한다. 

 

예를 들어  number= "1234568"이고 k=3인 경우 

총 4개의 숫자를 선택해야 하므로 , 0~3+0 범위 내에서 가장 큰 수를 택해야 된다. 

범위 내에서 가장 큰 수 4를 택하고 , 4~4+1 범위 내에서 가장 큰 수를 택해야 된다. 

이런 식으로 반복하여 4568이라는 가장 큰 수를 구할 수 있게 된다.

 

 

[코드]

 

#include <string>
#include <vector>

using namespace std;

string solution(string number, int k) {
    string answer = "";
    
    int tmp = number.size()-k;
    int idx =0;
    int tmp_idx=0;
    
    for(int i=0;i<tmp; i++)
    {
        int _max = number[idx]-'0';
        tmp_idx = idx;
        
        for(int j=idx; j<=k+i ; j++)
        {
            if(number[j]-'0' > _max ){
                _max =number[j]-'0'; 
                tmp_idx = j;
            }  
        }
        idx = tmp_idx+1;
        answer += to_string(_max);       
    }
    return answer;
}

 

[문제]

 

www.acmicpc.net/problem/2206

 

2206번: 벽 부수고 이동하기

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로

www.acmicpc.net

 

[풀이]

 

 

NXM으로 표현되는 맵이 문제 입력으로 주어진다.

맵에는 벽이 존재하는데 최대 한번 벽을 부수고 이동할 수 있다.

이 때 시작점에서 (N,M)까지의 최단 거리를 구하면 된다.

 

최단거리를 구하는 문제라서 BFS를 사용하고 pos 구조체에 crash 변수를 추가하여 이전 경로에서 벽을 부수고 왔는지를 확인했다.

원래 visited 배열은 2차원 배열로 아래와 같이 선언했었다.

int visited[MAX][MAX]

 

하지만 해당 위치를 이미 방문했더라도 벽을 부수고 왔는지 아닌지에 따라 결과가 달라지므로

벽을 부수고 왔는지 아닌지에 대해서도 확인할 수 있도록 아래와 같이 수정했다.

int visited[MAX][MAX][2]

 

 

[코드]

 

#include <iostream>
#include <queue>

#define MAX 1001

using namespace std;

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

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

struct pos{
    int x,y;
    bool crash;
};

int BFS()
{
    queue <pos> q;
    q.push({1,1,false});
    visited[1][1][0] =1;
    
    while(!q.empty()){
        
        int x = q.front().x;
        int y = q.front().y;
        bool check = q.front().crash;

        if(x == N && y == M)    return visited[x][y][check];
        
        q.pop();
        
        for(int i=0;i<4;i++){
            
            int nx = x+dx[i];
            int ny = y+dy[i];
            
            if(nx<1 || ny <1 || nx >  N || ny > M )  continue;
            if(map[nx][ny] == 1 && check)  continue;
            
            bool flag = false;
            if(map[nx][ny]==1)  flag = true;
            else    flag = check;
            
            if(visited[nx][ny][flag]!=0)    continue;
            
            q.push({nx,ny,flag});
            visited[nx][ny][flag]=visited[x][y][check]+1;
            
        }
    }
    return -1;
}

int main(void)
{
    scanf("%d %d",&N,&M);
    
    for(int i=1;i<=N;i++){
        for(int j=1;j<=M;j++){
            scanf("%1d",&map[i][j]);
        }
    }
    
    cout << BFS();
}

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

[백준] 2178. 미로탐색  (0) 2020.11.30
[백준] 2066. 바이러스  (0) 2020.11.30
[백준]2193. 이친수  (0) 2020.10.29
[백준]2096.내려가기  (0) 2020.10.29
[백준]1946. 신입사원  (0) 2020.10.17

[문제]

 

www.acmicpc.net/problem/2193

 

2193번: 이친수

0과 1로만 이루어진 수를 이진수라 한다. 이러한 이진수 중 특별한 성질을 갖는 것들이 있는데, 이들을 이친수(pinary number)라 한다. 이친수는 다음의 성질을 만족한다. 이친수는 0으로 시작하지 않

www.acmicpc.net

 

[풀이]

 

N이 1인 경우부터 모든 경우의 수를 구하다 보면 규칙을 금방 발견할 수 있다.

규칙을 통해 아래와 같이 점화식을 세워서 DP를 사용해 풀었다.

        DP[i] = DP[i-1]+DP[i-2];

 

[코드]

 

시간 : 0ms

 

#include <iostream>
#define MAX 90

using namespace std;

long long DP[MAX]={0,};
int N;

int main(void)
{
    cin >> N;
    DP[1] = 1;
    DP[2] = 1;
    
    for(int i=3;i<=N;i++)
    {
        DP[i] = DP[i-1]+DP[i-2];
    }
    cout << DP[N];
    return 0;
    
}

 

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

[백준] 2066. 바이러스  (0) 2020.11.30
[백준] 2206. 벽 부수고 이동하기  (0) 2020.10.30
[백준]2096.내려가기  (0) 2020.10.29
[백준]1946. 신입사원  (0) 2020.10.17
[백준]1197. 최소 스패닝 트리  (0) 2020.10.15

[문제]

www.acmicpc.net/problem/2096

 

2096번: 내려가기

첫째 줄에 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 N개의 줄에는 숫자가 세 개씩 주어진다. 숫자는 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 중의 하나가 된다.

www.acmicpc.net

 

[풀이]

 

DP를 사용해서 이전 경로까지의 최대, 최솟값을 저장해놓고

이전 경로와 현재 위치의 값을 더해서 최대, 최솟값을 구했다.

 

처음에는 N의 범위가 N(1 ≤ N ≤ 100,000)이므로 DP배열을 [100001][3]의 크기고 잡고 시작했는데 메모리 초과가 나왔다.

생각해보니 문제 조건에서 주어진 메모리 제한은 4MB인데 [100001][3]의 크기로 잡고 풀면

min, max 배열이 2개 이므로 4MB를 넘어버린다.

 

생각을 해보니 DP의 값을 계산할 때마다 필요한 값은 현재 위치의 값과 이전 위치의 값이므로

DP 배열의 크기를  [2][3]으로 바꾸고 아래와 같이 풀었다.

 

찾아보니 이러한 기법을 '슬라이딩 윈도우'라고 하는 것 같다.

 

[코드]

 

시간 : 24ms

 

#include <iostream>
#define _max(a,b) ((a) > (b) ? (a) : (b))
#define _min(a,b) ((a) < (b) ? (a) : (b))

using namespace std;

int N;
int map[3];
int DP_max[2][3]={0,};
int DP_min[2][3]={0,};

int main(void)
{
    scanf("%d",&N);
    
    for(int i=1;i<=N;i++)
    {
        scanf("%d %d %d",&map[0],&map[1],&map[2]);

        DP_max[1][0]=map[0] + _max(DP_max[0][0],DP_max[0][1]);
        DP_max[1][1]=map[1] + _max(DP_max[0][0],_max(DP_max[0][1],DP_max[0][2]));
        DP_max[1][2]=map[2] + _max(DP_max[0][1],DP_max[0][2]);
        
        DP_max[0][0]= DP_max[1][0];
        DP_max[0][1]= DP_max[1][1];
        DP_max[0][2]= DP_max[1][2];

        DP_min[1][0]=map[0] + _min(DP_min[0][0],DP_min[0][1]);
        DP_min[1][1]=map[1] + _min(DP_min[0][0],_min(DP_min[0][1],DP_min[0][2]));
        DP_min[1][2]=map[2] + _min(DP_min[0][1],DP_min[0][2]);

        DP_min[0][0]= DP_min[1][0];
        DP_min[0][1]= DP_min[1][1];
        DP_min[0][2]= DP_min[1][2];
    }
    
    cout << _max(DP_max[1][0],_max(DP_max[1][1],DP_max[1][2])) << " "<<_min(DP_min[1][0],_min(DP_min[1][1],DP_min[1][2]));
    
    return 0;
    
}

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

[백준] 2206. 벽 부수고 이동하기  (0) 2020.10.30
[백준]2193. 이친수  (0) 2020.10.29
[백준]1946. 신입사원  (0) 2020.10.17
[백준]1197. 최소 스패닝 트리  (0) 2020.10.15
[백준] 3020. 개똥벌레  (0) 2020.10.15

+ Recent posts