[문제]

https://www.codetree.ai/frequent-problems/tree-kill-all/description

 

코드트리

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

[풀이]

 

삼성전자 22년 상반기 SW 역량테스트 오후 2번 문제

 

1. 인접한 4개의 칸에 나무의 개수만큼 성장

2. 인접한 4개의 칸에 벽.다른 나무.제초제가 없는 칸에 대해 번식 진행

3. 나무가 가장 많이 박멸되는 곳에 제초제 뿌림

   - 벽 또는 나무가 없는 칸의 경우 그 이후 칸에는 제초제를 전파하지 못함

   - 이러한 칸이 여러개면 행이 작은 칸에 , 행이 같으면 열이 더 작은 칸에 제초제를 뿌린다.

 

각 스텝별로 api를 만들었다.

 

먼저 1번의 경우  growthTree에서 처리해줬다. 현재 나무가 존재하는 칸에 대해 인접한 칸의 나무가 존재하는 칸의 개수만큼 성장하도록 구현

 

2번의 경우 breedTree에서 조건문을 통해 제초제. 다른 나무. 벽의 존재 여부를 확인 후 없다면 번식을 진행하도록 구현해줬다.

 

그 다음으로 제초제는 매년 1씩 감소하므로 deleteHerb에서 제초제가 존재하는 칸에 대해 -1씩 해주었다.

 

마지막으로  dieTree에서 3번을 처리해주었다. 제초제를 뿌릴 수 있는 모든 칸에 대해 확인해주었다.

각 칸 마다 박멸하는 나무의 개수.행.열을 벡터에 저장하여 comp 함수를 통해 정렬을 해주었다.

 

또한 map에서는 나무가 없는 빈 칸과 제초제가 뿌려진 곳을 모두 0으로 처리하여 따로 구분해주지 않았다.

제초제가 뿌려진 곳은 herb 배열의 0이 아닌 칸이 되므로 빈칸과 제초제가 뿌려진 칸을 비교할 수 있다.

 

[코드]

//m년 동안 총 박멸한 나무의 그루 수를 구하는 프로그램을 작성해보세요

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

#define MAX 20

using namespace std;

struct info{
    int cnt,x,y;
};

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

int N,M,K,C;
int map[MAX][MAX]={0,};
int herbicide[MAX][MAX]={0,};
int res =0;

bool comp( info a, info b)
{
    if(a.cnt > b.cnt )  return true;
    else if(a.cnt < b.cnt )  return false;

    if(a.x < b.x )  return true;
    else if(a.x > b.x )  return false;

    if(a.y < b.y )  return true;
    return false;
}

void growthTree()
{
    int addTree[MAX][MAX]={0,};
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(map[i][j] <= 0)  continue;
            int cnt =0;
            for(int k=0;k<8;k+=2){
                int nx = i + dx[k];
                int ny = j + dy[k];

                if( nx < 0 || ny < 0 || nx >= N || ny >= N) continue;
                if( map[nx][ny] <= 0)   continue;
                cnt++;
            }
            addTree[i][j]=cnt;
        }
    }

    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            map[i][j] += addTree[i][j];
        }
    }
}

void breedTree()
{
    int addTree[MAX][MAX]={0,};

    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(map[i][j] <= 0)  continue;
            int cnt =0;
            for(int k=0;k<8;k+=2){
                int nx = i + dx[k];
                int ny = j + dy[k];

                if( nx < 0 || ny < 0 || nx >= N || ny >= N || map[nx][ny] != 0 || herbicide[nx][ny] != 0) continue;
                
                cnt++;
            }
            for(int k=0;k<8;k+=2){
                int nx = i + dx[k];
                int ny = j + dy[k];

                if( nx < 0 || ny < 0 || nx >= N || ny >= N || map[nx][ny] != 0 || herbicide[nx][ny] != 0) continue;
                addTree[nx][ny]+=map[i][j]/cnt;
            }
        }
    }

    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            map[i][j] += addTree[i][j];
        }
    }
}

void dieTree()
{
    vector<info> die;

    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if( map[i][j] <= 0)  continue;
            int cnt = map[i][j];
            for(int d=1;d<8;d+=2){
                for(int l=1;l<=K;l++){
                    int nx = i + dx[d]*l;
                    int ny = j + dy[d]*l;
                    if( nx < 0 || ny < 0 || nx >= N || ny >= N || map[nx][ny] <= 0) break;
                    cnt += map[nx][ny];
                }
            }
            if(cnt > 0)   die.push_back({cnt,i,j});
        }
    }
    

    
    if( die.size() == 0)    return ;
    sort(die.begin(), die.end(),comp);
    res += die[0].cnt;
    int x =die[0].x;
    int y =die[0].y;
    
    if( map[x][y] > 0){
        map[x][y] = 0;
        herbicide[x][y] = C;

        for(int d=1;d<8;d+=2){
            for(int l=1;l<=K;l++){
                int nx = x + dx[d]*l;
                int ny = y + dy[d]*l;
                if( nx < 0 || ny < 0 || nx >= N || ny >= N || map[nx][ny] <0 ) break;
                
                herbicide[nx][ny] = C;
                
                if( map[nx][ny] == 0 ){
                    break;
                } else {
                    map[nx][ny] = 0;
                }
            }
        }
    }
    
}

void deleteHerb()
{
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(herbicide[i][j] == 0)    continue;
            herbicide[i][j]-=1;
        }
    }
}

int main(void)
{
    cin >> N >> M >> K >> C;
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++)    cin >> map[i][j];
    }

    for(int i=0;i<M;i++){
        growthTree();
        breedTree();
        deleteHerb();
        dieTree();
    }
    cout << res;
    return 0;
}

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

[코드트리] 동전 챙기기 ( C++)  (0) 2022.10.15
[코드트리] 예술성 (C++)  (0) 2022.10.13
[코드트리] 술래잡기 (C++)  (0) 2022.10.10

[문제]

https://www.acmicpc.net/problem/20056

 

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

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

www.acmicpc.net

 

[풀이]

 

N*N 격자에 파이어볼 M개가 존재한다.

각 파이어볼은 질량(m), 속력(s), 방향(d)을 가지고 있다.

 

1. 모든 파이어볼이 d 방향으로 s만큼 움직인다,.

2. 2개 이상의 파이어볼이 있는 칸은 하나의 파이어볼로 합쳐진다.

 - 합쳐진 파이어볼은 4개의 파이어볼로 나뉘어진다.

- 각 파이어볼의 질량은 ( 합쳐진 파이어볼의 질량 합 / 5 )

- 각 파이어볼의 속력은 ( 합쳐진 파이어볼의 속력 합 / 파이어볼의 개수) 

- 모든 파이어볼의 방향이 홀수 또는 짝수로 일치할 경우 나뉘어진 파이어볼의 방향은 0,2,4,6이 되고 아닌 경우 1,3,5,7이 된다.

 

1번과 2번에 대해 각각의 api로 관리했다. 파이어볼이 이동하는 것은 moveBall에서 처리하고 파이어볼이 나뉘어 지는 것은 divideBall api에서 처리해주었다.

 

첫번째로 moveBall에서 파이어볼을 이동시켰다.

문제에서 주어진 조건으로 격자의 행과 열은 1번부터 N번까지 번호가 매겨져 있고, 1번 행은 N번과 연결되어 있고, 1번 열은 N번 열과 연결되어 있다. 

 

따라서 (1,1)을 기준으로 시작하여 s%N 만큼 이동하도록 해주었다. 또한 이동한 위치가 1보다 작거나 N보다 클 경우 N만큼 빼주거나 더해주어 이동위치를 계산했다.

 

그리고 두번째로 이동한 파이어볼에 대해 문제 조건에 맞게 divideBall에서 파이어볼을 나눠주도록 처리했다.

 

 

[코드]

#include <iostream>
#include <vector>
#include <cmath>
#define MAX 51

using namespace std;

struct Ball{
    int m,s,d;
};
int N,M,K;
int dx[8]={-1,-1,0,1,1,1,0,-1};
int dy[8]={0,1,1,1,0,-1,-1,-1};

vector<Ball> fireBall[MAX][MAX];

void moveBall()
{
    vector<Ball> tmpBall[MAX][MAX];
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            for(int k=0;k<fireBall[i][j].size();k++){
                int s= fireBall[i][j][k].s%N;
                int d= fireBall[i][j][k].d;
                
                int nx = i+dx[d]*s;
                int ny = j+dy[d]*s;
                
                
                if(nx < 1)   nx+=N;
                if(nx > N) nx -=N;
                
                if(ny < 1)   ny+=N;
                if(ny > N) ny-= N;
                
                tmpBall[nx][ny].push_back(fireBall[i][j][k]);
            }
        }
    }
    
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            fireBall[i][j].clear();
            fireBall[i][j] = tmpBall[i][j];
        }
    }
}

void divideBall()
{
    vector<Ball> tmpBall[MAX][MAX];

    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            if ( fireBall[i][j].size() == 1){
                tmpBall[i][j] = fireBall[i][j];
            }
            else if ( fireBall[i][j].size() >= 2){
                int totalS=0;
                int totalM=0;
                bool even=false;
                bool odd=false;
                
                for(int k=0;k<fireBall[i][j].size();k++){
                    int dir=fireBall[i][j][k].d;
                    if(dir % 2 == 0)    even = true;
                    else    odd = true;
                    
                    totalS+=fireBall[i][j][k].s;
                    totalM+=fireBall[i][j][k].m;
                }
                
                int m = totalM/5;
                int s = totalS/fireBall[i][j].size();
                int dir = even && odd ? 1 : 0;
                 if ( m > 0)
                 {
                     for(int d=dir;d<8;d+=2){
                        tmpBall[i][j].push_back({m,s,d});
                    }
                 }
            }
            fireBall[i][j].clear();
            fireBall[i][j] = tmpBall[i][j];
        }
    }
    
}

int main(void)
{
    ios::sync_with_stdio(false);
    
    cin >> N >> M >> K;
    
    for(int i=0;i<M;i++){
        int x,y,m,s,d;
        cin >> x >> y >> m >> s >> d;
        fireBall[x][y].push_back({m,s,d});
    }
    for(int i=0;i<K;i++){
        moveBall();
        divideBall();
    }
    
    long long totalM =0;
    
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            for(int k=0;k<fireBall[i][j].size();k++)    totalM+=fireBall[i][j][k].m;
        }
    }
    
    cout << totalM;
    return 0;
}

[문제]

https://www.acmicpc.net/problem/20058

 

20058번: 마법사 상어와 파이어스톰

마법사 상어는 파이어볼과 토네이도를 조합해 파이어스톰을 시전할 수 있다. 오늘은 파이어스톰을 크기가 2N × 2N인 격자로 나누어진 얼음판에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c

www.acmicpc.net

 

[풀이]

 

파이어스톰은 먼저 격자를 2L × 2L 크기의 부분 격자로 나눈다. 그 후, 모든 부분 격자를 시계 방향으로 90도 회전시킨다.

격자별 회전을 처리해주기 위해 rotate api의 인자로 각 격자의 시작 점과 길이를 넘겨주도록 했다.

 

(0,0)을 기준으로 90도 시계 방향 회전하면 (x,y) -> (y, (N-1)-x)로 위치가 변한다.

그런데 해당 문제에서는 격자별로 90도 회전이므로 0부터 len 이전까지 반복하면서 tmp 배열에 (0,0)부터 회전한 값을 저장한다.

tmp[j][len-1-i] = map[x+i][y+j];

그리고 tmp (0,0)부터 (len-1,len-1) 까지 다시 map 배열로 옮겨준다.

map[x+i][y+i] = tmp[i][j];

이와 같은 방식으로 90도 회전을 구현했다.

 

회전 후 melt_ice api를 통해 얼음을 녹여준다.

 

그리고 find_max_lump api에서 남아있는 얼음의 합을 구하고 가장 큰 덩어리가 차지하는 칸의 개수를 출력해줬다. 

 

 

[코드]

 

#include <iostream>
#include <queue>

#define MAX 70

using namespace std;

struct pos {
    int x,y;
};

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

int N,Q,L;
int map[MAX][MAX]={0,};

// 격자 시계방향 회전
void rotate(int x, int y, int len){
    int tmp[MAX][MAX]={0,};

    for(int i=0;i<len;i++)
        for(int j=0;j<len;j++)
            tmp[j][len-1-i]=map[x+i][y+j];
    for(int i=0;i<len;i++)
        for(int j=0;j<len;j++)
            map[x+i][y+j]=tmp[i][j];
}

void rotate_grid()
{
    int len = 1 << L;
    
    for(int i=0;i<N;i+=len){
        for(int j=0;j<N;j+=len){
            rotate(i,j,len);
        }
    }
}

void melt_ice()
{
    int tmp[MAX][MAX]={0,};
    
    for(int x=0;x<N;x++){
        for(int y=0;y<N;y++){
            int cnt =0;
            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) continue;
                if( map[nx][ny] != 0 )  cnt++;
            }
            if (cnt < 3) {
                if( map[x][y] != 0) tmp[x][y] = map[x][y] -1;
            }
            else tmp[x][y] = map[x][y];
        }
    }

    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            map[i][j] = tmp[i][j];
        }
    }

}

int find_max_lump()
{
    bool visited[MAX][MAX]={0,};
    int res =0;
    queue<pos> q;
    int sum=0;
    
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            int cnt =0;
            sum += map[i][j];
            if(map[i][j] <= 0 || visited[i][j] )
                continue;
        
            q.push({i,j});
            visited[i][j]=1;
            
            while(!q.empty()){
                cnt++;
                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] || map[nx][ny] <= 0)    continue;
                    visited[nx][ny] = 1;
                    q.push({nx,ny});
                }
            }
            if( res < cnt)  res = cnt;
        }
    }
    cout << sum << "\n";
    return res;
}

int main(void)
{
    std::ios::sync_with_stdio(false);

    cin >> N >> Q;
    N = 1 << N;
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++)    cin >> map[i][j];
    }
    for(int i=0;i<Q;i++){
        cin >> L;
        rotate_grid();
        melt_ice();
    }
    cout << find_max_lump();
    return 0;
}

[문제]

https://www.codetree.ai/frequent-problems/hide-and-seek/description

 

코드트리

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

[풀이]

 

삼성 22 상반기 SW 역량 오전 1번 문제로 달팽이 회전에 잘 처리해준다면 문제 없이 해결할 수 있는 문제인 것 같다.

 

  1. m명의 도망자가 움직인다.
    1. 이 때 술래와 거리가 <=3인 도망자만 움직인다.
    2. 움직이려는 칸에 술래가 있으면 움직이지 않고 나무가 있는 경우는 움직여도 된다.
    3. 움직이려는 위치가 격자를 벗어난다면 방향을 틀고 움직인다. 이 때도 마찬가지로 술래가 있다면 방향만 틀고 움직이지 않는다.
  2. 술래가 한칸 움직인다. 
    1. 술래는 달팽이 방향으로 움직이고 이동 후 위치가 방향 트는 부분이면 바로 튼다.
  3. 술래가 도망자를 잡는다.
    1. 현재 술래의 방향을 기준으로 현재 칸(술래가 존재하는 칸) 포함 3칸에 존재하는 도망자를 잡을 수 있다.
    2. 해당 칸에 나무가 존재한다면 도망자를 잡지 못한다.
    3. 이 때 도망자를 잡으면 점수를 얻게 되는데 t 번째 턴에 잡은 도망자 수를 곱하여 ( t * 도망자 수) 가 점수가 된다.

이런식으로 반복하여 도망자를 잡아 얻은 점수를 출력하면 된다.

위의 과정을 각각 api로 나눠서 구현했다.

도망자가 움직이는 과정은 moveRunner. 술래가 움직이는건 moveSullae, 도망자가 잡히는건 catchRunner 

 

첫번째로 moveRunner에서 술래와 거리가 3 이하인 도망자만 움직이도록 구현했다.

도망자 정보는 이차원 배열 벡터를 사용해 관리하고 도망자가 움직인 정보를 tmpRuunerMap이라는 변수에 담아뒀다가 모든 도망자가 이동하면 기존 runnerMap을 초기화 하고 tmpRunnerMap의 정보를 runnerMap으로 옮겨줬다.

 

두번째로 moveSullae api에서 술래가 움직인다. 술래는 달팽이 방향으로 1번의 턴에 한칸씩 움직인다. 달팽이 방향 회전은 1,1,2,2,3,3,4,4, 이런식으로 같은 길이가 두번씩 반복하고 길이가 1 추가된다. 따라서 전역 변수로 len과 cnt를 선언해주어 해당 길이를 몇 번 돌았는지 체크해준다. 이 때 cnt가 2가 되면 len을 1 추가해주었다. 또한 len 만큼 다 돌면 방향을 틀게끔 sullae의 dir을 업데이트 해주었다. 또한 술래가 정방향으로 한바퀴 다 돌고나면 다시 역방향으로 돌아야 하므로 opposite라는 전역변수를 추가해주어 역방향인지 정방향인지 구분해주었다. 또한 len 만큼 다 돌아서 술래가 방향을 틀어야하는 위치인 경우에 방향도 바로 업데이트 해주었다.

 

마지막으로 catchRunner에서 현재 술래의 위치를 기준으로 술래 방향으로 3칸 이내에 존재하는 도망자를 잡도록 해주었다.

 

 

[코드]

 

#include <iostream>
#include <vector>
#define MAX 100
using namespace std;

struct Info{
    int x,y,dir;
};

Info sullae;

bool namu[MAX][MAX]={0,};
vector<int> runnerMap[MAX][MAX];
// int map[MAX][MAX]={0,};

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};
int N,M,H,K;
bool opposite= false;
int len, cnt;
//목표 len
int curLen= 1;
void moveRunner()
{
    vector<int> tmpRunnerMap[MAX][MAX];

    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            for(int k=0;k<runnerMap[i][j].size();k++){
                
                int d= runnerMap[i][j][k];
                int dis = abs(i-sullae.x) + abs(j-sullae.y);
                if(dis > 3) {
                    tmpRunnerMap[i][j].push_back(runnerMap[i][j][k]);
                    continue;
                }

                int nx = i+dx[d];
                int ny = j+dy[d];

                if( nx < 0 || ny < 0 || nx >= N || ny >= N) {
                    if( d < 2)  d += 2;
                    else    d -= 2;

                    nx = i + dx[d];
                    ny = j + dy[d];
                }

                if ( nx == sullae.x && ny == sullae.y)  {
                    nx = nx - dx[d];
                    ny = ny - dy[d];
                }

                tmpRunnerMap[nx][ny].push_back(d);
            }
        }
    }
    
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            runnerMap[i][j].clear();
            runnerMap[i][j] = tmpRunnerMap[i][j];
        }
    }

}

int catchRunner()
{
    int x = sullae.x;
    int y = sullae.y;
    int dir = sullae.dir;

    int cnt =0;
    for(int i=0;i<3;i++)
    {
        int nx = x+dx[dir]*i;
        int ny = y+dy[dir]*i;
        if( namu[nx][ny])   continue;
        if( nx <0 || ny <0 || nx >= N || ny >= N)   break;

        if( runnerMap[nx][ny].size() > 0){
            cnt += runnerMap[nx][ny].size();
            runnerMap[nx][ny].clear();
        }
    }
    return cnt;
}

void moveSullae()
{
    int x =sullae.x;
    int y =sullae.y;
    int dir = sullae.dir;

    int nx = x+dx[dir];
    int ny = y+dy[dir];

    len++;

    if ( len == curLen ) {
        len=0;
        cnt++;
        if( opposite == false){
            if(dir == 3)    dir = 0;
            else    dir++;
        }
        else {
            if ( dir == 0 ) dir = 3;
            else    dir--;
        }
        if (cnt == 2)  {
            cnt = 0;
            if(!opposite)    curLen++;
            else    curLen--;

        }
    }

    if(nx == 0 && ny == 0){
        opposite= true;
        curLen = N-1;
        dir = 2;
        cnt = -1;
        len = 0;
    } else if(nx == (N-1)/2 && ny == (N-1)/2) {
        opposite= false;
        curLen=1;
        dir = 0;
        cnt = 0;
        len = 0;
    }
    sullae = {nx,ny,dir};
}

int main(void)
{
    ios::sync_with_stdio(false);

    curLen = 1;
    len = 0;
    cnt = 0;

    cin >> N >> M >> H >> K;
    sullae = { (N-1)/2, (N-1)/2,0};
    
    for(int i=0;i<M;i++){
        int x,y,d;
        cin >> x >> y >> d;
        if( d==1)   d = 1;
        else    d = 2;
        runnerMap[x-1][y-1].push_back(d);
    }
    
    for(int i=0;i<H;i++){
        int x,y;
        cin >> x >> y;
        namu[x-1][y-1] = 1;
    }

    int score =0;
    
    for(int i=1;i<=K;i++){
       moveRunner();
        moveSullae();
       score += i * catchRunner();
    }
    cout << score;
    return 0;
}

 

그리고 (N-1)/2 해줄 때 괄호 빼먹어서 계속 틀렸다...조심하자 

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

[코드트리] 동전 챙기기 ( C++)  (0) 2022.10.15
[코드트리] 예술성 (C++)  (0) 2022.10.13
[코드트리] 나무박멸 (C++)  (0) 2022.10.12

[문제]

 

https://www.acmicpc.net/problem/21611

 

21611번: 마법사 상어와 블리자드

마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그, 비바라기 마법을 할 수 있다. 오늘 새로 배운 마법은 블리자드이고, 크기가 N×N인 격자에서 연습하려고 한다. N은 항상 홀수이고, (

www.acmicpc.net

 

[풀이]

 

  1. 상어가 구슬 파괴
  2. 구슬 이동
  3. 구슬 폭발
    1. 4개 이상 연속하는 구슬
  4. 구슬 이동
  5. 구슬 변화
    1. 하나의 그룹 => 구슬 A,B (  A는 구슬의 개수 , B는 구슬 번호)

위와 같은 과정이 M번 반복해서 일어난다.

1번부터 5번까지의 각 과정을 api로 분리하여 구현했다.

 

상어가 구슬을 파괴하는 과정은 destruct_bead , 구슬이 이동하는 과정은 move_bead, 구슬이 폭발 후 이동하는 과정은  explode_bead, 구슬이 변화하는 과정은 change_bead에서 처리하도록 구현했다. 

 

또한 모든 과정이 달팽이 모양 회전을 기반으로 발생한다.

 

첫번째로 상어가 구슬을 파괴하는 과정은 현재 상어 위치를 기반으로 d 방향으로  s 거리만큼에 존재하는 구슬을 파괴하므로 for 문을 통해 간단하게 구할 수 있다. 

 

두번째로 구슬이 이동하는 과정을 달팽이 모양을 기반으로 회전한다. 또한 회전하는 길이가 1,1,2,2,3,3,4,4,5,5,... 이런식으로 2번씩 같은 길이를 반복하고 방향이 바뀌면서 길이가 +1이 되는 구조이다. 따라서 이중 for문의 바깥 for문에서는 2번을 count 해주고 내부 for문에서는 len 만큼 반복할 수 있도록 처리해줬다. 현재 길이를 두번 다 돌면 길이를 +1 해주도록 처리했고 영역을 벗어나는 경우에 while문을 빠져나오도록 조건을 걸었다. 달팽이 방향으로 한칸씩 다 돌면서 bead라는 일차원 배열을 선언하여 map에서 0이 아닌 값들에 대해서만 옮겨준다. 모든 map에 대해 한바퀴 다 돌고 나면 기존 map을 0으로 초기화 해주고 bead에 존재하는 값들을 복사해준다. 이때도 마찬가지로 달팽이 방향으로 회전하도록 했다.

 

세번째로 4개 이상 동일한 구슬이 반복되는 것에 대해 그룹화 하여 폭발시켜줬다. 이 때 문제에서 출력해야 되는 것은 폭발된 구슬의 개수이므로 explode_cnt라는 배열을 선언하여 각 구슬별 폭발된 개수를 저장해놨다. 구슬 이동과 마찬가지로 하나의 길이에 대해 두번씩 카운트 하면서 길이를 +1씩 해주었다. 이와 같이 달팽이 방향으로 돌면서 연속하는 구슬이 4개 이상인 경우 폭발 시켜줬다. bead 라는 벡터를 선언하여 폭발되지 않은 구슬만 담아줬다. 이런식으로 폭발할 구슬을 찾으면 한번 더 확인을 해줘야한다. 예를들어 구슬이 111222211111 이렇게 있으면 bead라는 벡터에 11111111이 존재하는데 이것도 연속된 구슬이 4개 이상이므로 폭발해야 하는 구슬이다. 따라서 bead에 대해서 한번 더 돌면서 연속되는 구슬이 있는지 확인해주고 update_bead 라는 벡터에 담아줬다.. 원래 구슬 폭발 후 바로 이동을 해야하는데 모든 그룹에 대해 폭발을 다 하고 이동하는식으로 구현해서 이렇게 된 것 같다. 이 부분에 대해서는 한번 더 고려해봐야겠다. 이렇게 구슬을 폭발하고  update_bead에 존재하는 구슬을 달팽이 방향으로 map에 옮겨줬다.

 

마지막으로 구슬을 그룹화하여 구슬 개수, 구슬 번호로 구슬을 change 해줬다. 여기서도 마찬가지로 달팽이 방향으로 돌면서 확인해줬다.

 

이와 같이 위의 방식을 M번 수행 후 각 구슬별 폭발된 구슬의 개수를  count 하여 출력해줬다.

 

유사 문제로는 

2022 상반기 오전 문제가 있는데 참고해보면 좋을 것 같다.

 

[코드]

 

#include <iostream>
#include <vector>
#include<string.h>
#define MAX 50

using namespace std;

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

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

void destruct_bead(int d,int s)
{
    int x = (N+1)/2;
    int y = (N+1)/2;
    
    for(int i=1;i<=s;i++){
        int nx = x + dx[d]*i;
        int ny = y + dy[d]*i;
        
        if( nx <= 0 || ny <= 0 || nx > N || ny > N )    break;
        map[nx][ny] =0;
    }
}

void move_bead()
{
    int tmp[MAX][MAX]={0,};
    
    int bead[MAX*MAX]={0,};
    int x= (N+1)/2;
    int y= (N+1)/2;
    int dir =3;
    int len = 1;
    int idx =0;
    bool flag=true;
    
    
    while(flag){
        for(int j=0;j<2;j++){
            for(int i=0;i<len;i++){
                x+=dx[dir];
                y+=dy[dir];
                
                if ( x <= 0 || y<= 0 || x > N || y > N ){
                    flag=false;
                    break;
                }
                
                if(map[x][y] != 0){
                    bead[idx] = map[x][y];
                    idx++;
                }
            }
            if(!flag)   break;
            
            if(dir == 1)    dir = 3;
            else if ( dir == 2) dir = 4;
            else if ( dir == 3) dir = 2;
            else if ( dir == 4) dir = 1;
        }
        len++;
    }
    
    x= (N+1)/2;
    y= (N+1)/2;
    dir =3;
    len = 1;
    idx =0;
    flag=true;
    
    
    for(int i=1;i<=N;i++){
        for(int j=0;j<=N;j++)   map[i][j]=0;
    }
               
    while(flag){
        for(int j=0;j<2;j++){
            for(int i=0;i<len;i++){
                x+=dx[dir];
                y+=dy[dir];
                
                if ( bead[idx] == 0){
                    flag=false;
                    break;
                }
                map[x][y] = bead[idx];
                idx++;
            }
            if(!flag)   break;
            
            if(dir == 1)    dir = 3;
            else if ( dir == 2) dir = 4;
            else if ( dir == 3) dir = 2;
            else if ( dir == 4) dir = 1;
        }
        len++;
    }
    
}

void explode_bead()
{
    int tmp[MAX][MAX]={0,};
    
    vector<int> bead;
    
    int x = (N+1)/2;
    int y = (N+1)/2;
    int dir =3;
    int len = 1;
    int idx =0;
    bool flag=true;
    
    
    int cur = -1;
    int cnt = 0;
    
    while(flag){
        for(int j=0;j<2;j++){
            for(int i=0;i<len;i++){

                x+=dx[dir];
                y+=dy[dir];

                if ( x <= 0 || y<= 0 || x > N || y > N || cur == 0){
                    flag=false;
                    break;
                }
                

                if(map[x][y] == cur){
                    cnt++;
                } else {
                    if( cnt >= 4 ){
                        explode_cnt[cur] += cnt;
                        for(int k=0;k<cnt;k++)  bead.pop_back();
                    }
                    cur = map[x][y];
                    cnt = 1;
                }
                bead.push_back(map[x][y]);
            }
            if(!flag)   break;
            
            if(dir == 1)    dir = 3;
            else if ( dir == 2) dir = 4;
            else if ( dir == 3) dir = 2;
            else if ( dir == 4) dir = 1;
        }
        len++;
    }
    
    vector<int> update_bead;
    
    cnt=0;
    cur = -1;
    while(1){
        bool duplicate = false;
        for(int i=0;i<bead.size();i++){
            if(bead[i] == cur){
                cnt++;
            } else {

                if( cnt >= 4 ){
                    duplicate= true;
                    explode_cnt[cur] += cnt;
                    for(int k=0;k<cnt;k++)  update_bead.pop_back();
                }
                cur = bead[i];
                cnt = 1;
            }
            update_bead.push_back(cur);

        }
        if( !duplicate )    break;
        else{
            bead.clear();
            bead = update_bead;
            update_bead.clear();
        }
    }
    
    x= (N+1)/2;
    y= (N+1)/2;
    dir =3;
    len = 1;
    idx =0;
    flag=true;
    while(flag){
        for(int j=0;j<2;j++){
            for(int i=0;i<len;i++){
                x+=dx[dir];
                y+=dy[dir];
                
                if ( idx == update_bead.size()){
                    flag=false;
                    break;
                }
                tmp[x][y] = update_bead[idx];
                idx++;
            }
            if(!flag)   break;
            
            if(dir == 1)    dir = 3;
            else if ( dir == 2) dir = 4;
            else if ( dir == 3) dir = 2;
            else if ( dir == 4) dir = 1;
        }
        len++;
    }
    
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++)    map[i][j] = tmp[i][j];
    }
}

void bead_change()
{
    
    int tmp[MAX][MAX]={0,};
    
    vector<int> bead;
    
    int x = (N+1)/2;
    int y = (N+1)/2;
    int dir = 3;
    int len = 1;
    int idx = 0;
    bool flag=true;
    
    
    int cur = -1;
    int cnt = 0;
    
    while(flag){
        for(int j=0;j<2;j++){
            for(int i=0;i<len;i++){

                x+=dx[dir];
                y+=dy[dir];

                if ( x <= 0 || y<= 0 || x > N || y > N || cur == 0){
                    flag=false;
                    break;
                }

                if(map[x][y] == cur){
                    cnt++;
                } else {
                    if(cnt>0){
                        bead.push_back(cnt);
                        bead.push_back(cur);
                    }
                    cur = map[x][y];
                    cnt = 1;
                }
            }
            if(!flag)   break;
            
            if(dir == 1)    dir = 3;
            else if ( dir == 2) dir = 4;
            else if ( dir == 3) dir = 2;
            else if ( dir == 4) dir = 1;
        }
        len++;
    }
    
    x= (N+1)/2;
    y= (N+1)/2;
    dir =3;
    len = 1;
    idx =0;
    flag=true;
    while(flag){
        for(int j=0;j<2;j++){
            for(int i=0;i<len;i++){
                x+=dx[dir];
                y+=dy[dir];
                
                if (x <= 0 || y<= 0 || x > N || y > N || idx == bead.size()){
                    flag=false;
                    break;
                }
                tmp[x][y] = bead[idx];
                idx++;
            }
            if(!flag)   break;
            
            if(dir == 1)    dir = 3;
            else if ( dir == 2) dir = 4;
            else if ( dir == 3) dir = 2;
            else if ( dir == 4) dir = 1;
        }
        len++;
    }
    
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++)    map[i][j] = tmp[i][j];
    }
    
}


int main(void)
{
    cin >> N >> M;
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++)    cin >> map[i][j];
    }
    
    for(int i=0;i<M;i++){
        int d,s;
        cin >> d >> s;
        destruct_bead(d,s);
        move_bead();
        explode_bead();
        bead_change();
    }
    
    cout << explode_cnt[1] * 1 + explode_cnt[2] * 2 + explode_cnt[3] * 3;
    return 0;
}

[문제]

https://school.programmers.co.kr/learn/courses/30/lessons/92341

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

[풀이]

 

차량의 입/출차 시간을 통해 주차 요금을 계산하는 문제

map을 사용해 차량 번호가 key 값이 되고 입/출차 시간이 value가 되도록 구현했다.

map의 value 사이즈가 홀수인 경우 출차 시간이 찍히지 않은 차량이므로 23:59를 insert 해주었다.

각 차량 번호별로 value에서 2개씩 데이터를 가져와 주차 시간을 구했고 모두 더하여 주차 요금을 계산했다.

 

[코드]

#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <cmath>
using namespace std;

map<string,vector<string>> time_info;

int time_diff(string in, string out){
    int h1 = stoi(in.substr(0, 2));
    int m1 = stoi(in.substr(3, 2));
    
    int h2 = stoi(out.substr(0, 2));
    int m2 = stoi(out.substr(3, 2));
    
    return (h2-h1)*60 + (m2-m1);
}
vector<int> solution(vector<int> fees, vector<string> records) {
    vector<int> answer;
    stringstream ss;
    for(int i=0;i<records.size();i++){
        ss.str(records[i]);
        string t, number, status;
        ss >> t >> number >> status;
        
        time_info[number].push_back(t);
        ss.clear();
        
    }
    for(auto it: time_info) {

        if(it.second.size() % 2) {
            it.second.push_back("23:59");   
        }
        vector<string> info = it.second;
        int total =0;
        for(int i=0;i<info.size();i+=2){
            total += time_diff(info[i], info[i+1]);
        }
        int fee = fees[1];
        if( total> fees[0]){
            fee += ceil((total-fees[0])/(double)fees[2])* fees[3];
        }
        answer.push_back(fee);
    }
    return answer;
}

[문제]

https://school.programmers.co.kr/learn/courses/30/lessons/17677

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

[풀이]

 

input string에 대해 두 글자씩 끊어서 다중 집합을 만들고 두 집합 간의 교집합/합집합 * 65536을 구해서 return 해주면 되는 문제

 

첫 번째로 각 input string에 대해 모두 lower case로 변환해주었다.

다음으로 연속된 두 글자가 알파벳인 경우 vector에 push 해주었다.

 

이중 for문을 통해 교집합을 구하고 교집합의 중복을 막기 위해 한번 확인한 글자는 #로 변환해주었다.

 

[코드]

 

#include <string>
#include <cmath>
#include <vector>
using namespace std;

bool isChar(char ch){
    if(ch>='a' && ch<='z')  return true;
    if(ch>='A' && ch<='Z')  return true;
    return false;
}

int solution(string str1, string str2) {
    int answer = 0;
    string tmp1="";
    string tmp2="";
    
    for(int i=0;i<str1.size();i++){
        str1[i]=tolower(str1[i]);
    }
    for(int i=0;i<str2.size();i++){
        str2[i]=tolower(str2[i]);
    }
    
    vector<string> p1;
    vector<string> p2;
    for(int i=0;i<str1.size()-1;i++){
        if(isChar(str1[i]) && isChar(str1[i+1]))
            p1.push_back(str1.substr(i,2));
    }    
    for(int i=0;i<str2.size()-1;i++){
        if(isChar(str2[i]) && isChar(str2[i+1]))
            p2.push_back(str2.substr(i,2));
    }
    
    int intersection=0; //교집합
    int _union= p1.size()+ p2.size(); //합집합
    
    for(int i=0;i<p1.size();i++){
        for(int j=0;j<p2.size();j++){
            if(p1[i]==p2[j]){
                intersection++;
                p2[j]="#";
                break;
            } 
        }
    }
    _union-=intersection;
    if(_union == 0)    return 65536;
    answer = intersection * 65536 /_union;
    return answer;
}

 

문제

 

https://school.programmers.co.kr/learn/courses/30/lessons/118666?language=cpp

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

풀이

 

검사자의 선택지 사이즈만큼 반복하여 결과를 구한다.

map을 사용하여 각 유형의 점수를 관리하였다.

이와 같이 점수를 다 구하여 각 지표별 성격 유형을 구한다.

 

코드

 

#include <string>
#include <vector>
#include <map>

using namespace std;

int score[8] = {0,3,2,1,0,1,2,3};


string solution(vector<string> survey, vector<int> choices) {
    string answer = "";
    map <char, int> m;
    for( int i=0;i<survey.size();i++) {
        string sur= survey[i];
        int ans= choices[i];

        m[sur[ans/4]] += score[ans];
    }
    
    answer += m['R'] >= m['T'] ? "R" : "T";
    answer += m['C'] >= m['F'] ? "C" : "F";
    answer += m['J'] >= m['M'] ? "J" : "M";
    answer += m['A'] >= m['N'] ? "A" : "N";

    return answer;
}

+ Recent posts