www.acmicpc.net/problem/1780

 

1780번: 종이의 개수

N×N크기의 행렬로 표현되는 종이가 있다. 종이의 각 칸에는 -1, 0, 1의 세 값 중 하나가 저장되어 있다. 우리는 이 행렬을 적절한 크기로 자르려고 하는데, 이때 다음의 규칙에 따라 자르려고 한다.

www.acmicpc.net

<풀이>

1. 정사각형 종이의 한 변 크기인 N과 종이의 모양을 입력받는다.

2. 해당 종이를 지정한 방식으로 잘랐을 때, 각 종류별 종이의 개수를 출력한다.

 

<해법>

1. 자르는 방식을 분석하는 방법

=> 주어진 종이를 9부분으로 나누고 같은 방식으로 종이를 계속 잘라 나갑니다. 여기서 분할 정복을 사용해야 한다는 생각을 할 수 있습니다. 각 부분마다 같은 숫자가 쓰여져 있는지 확인하고, 아닌 경우 계속 잘라나가는 방식으로 구현하였습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <string.h>
 
using namespace std;
 
int N;
int map[2200][2200];
//[0]:-1종이 개수, [1]:0종이 개수, [2]:1종이 개수
int answer[3];
 
//모두 같은 숫자인지 판단
bool allSameNumber(int x, int y, int n) {
    
    int check = map[x][y];
 
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (map[x + i][y + j] != check) {
                return false;
            }
        }
    }
 
    return true;
}
 
void makePaper(int x, int y, int n) {
 
    //종이가 모두 같은 숫자일 경우 -> 해당 종이 갯수 + 1, 종료
    if (allSameNumber(x, y, n)) {
        int paperNum = map[x][y];
        answer[paperNum + 1]++;
        return;
    }
 
    int div = n / 3;
 
    //9개로 나누어서 분할 정복
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            makePaper(x + div * i, y + div * j, div);
        }
    }
}
 
int main() {
 
    //초기화
    N = 0;
    memset(map, 0sizeof(map));
    memset(answer, 0sizeof(answer));
 
    //입력
    cin >> N;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cin >> map[i][j];
        }
    }
 
    //해법
    /*
    9개로 나누어서 분할 정복
    */
    makePaper(00, N);
 
    //출력
    for (int i = 0; i < 3; i++) {
        cout << answer[i] << "\n";
    }
 
    //종료
    return 0;
}
 

 

분할 정복에 대해 알아볼 수 있는 문제였습니다.

www.acmicpc.net/problem/2447

 

2447번: 별 찍기 - 10

재귀적인 패턴으로 별을 찍어 보자. N이 3의 거듭제곱(3, 9, 27, ...)이라고 할 때, 크기 N의 패턴은 N×N 정사각형 모양이다. 크기 3의 패턴은 가운데에 공백이 있고, 가운데를 제외한 모든 칸에 별이

www.acmicpc.net

<풀이>

1. 정사각형 한 변의 길이인 N을 입력받는다.

2. N x N 정사각형에 주어진 패턴대로 출력한다.

 

<해법>

1. 주어진 패턴 분석하는 방법

=> 주어진 패턴은 총 9부분으로 나누어서 생각할 수 있습니다. 나누어진 9부분을 또 더 탐색해야할 8부분과 탐색할 필요없는 가운데 부분으로 나눌 수 있습니다. 

 

2. N x N 정사각형 출력하는 방법

=> 분할 정복을 끝냈다면, 이제는 출력을 해야 합니다. 저는 N x N 정사각형 배열을 만들어서, 배열에 분할 정복된 패턴을 담아주는 방식으로 구현하였습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <string.h>
 
using namespace std;
 
int N;
char map[2200][2200];
 
//x,y : 좌표, n : 한 변의 길이
void makeStar(int x, int y, int n) {
 
    //더이상 나눌 수 없는 지점
    if (n == 1) {
        map[x][y] = '*';
        return;
    }
 
    int div = n / 3;
 
    //9부분으로 나누기
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
 
            //가운데 지점은 빈 칸으로 채우기
            if (i % 3 == 1 && j % 3 == 1) {
 
                for (int k = 0; k < div; k++) {
                    for (int l = 0; l < div; l++) {
                        map[x + i + k][y + j + l] = ' ';
                    }
                }
 
                continue;
            }
 
            //나머지 8부분 탐색
            makeStar(x + div * i, y + div * j, div);
        }
    }
}
 
int main() {
 
    //초기화
    N = 0;
    memset(map, '#'sizeof(map));
 
    //입력
    cin >> N;
 
    //해법
    /*
    9등분으로 나누어서 분할 정복
    */
    makeStar(00, N);
 
    //출력
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cout << map[i][j];
        }
        cout << "\n";
    }
 
    //종료
    return 0;
}
 

 

분할 정복과 구현에 대해 알아볼 수 있는 문제였습니다.

algospot.com/judge/problem/read/QUADTREE

 

algospot.com :: QUADTREE

쿼드 트리 뒤집기 문제 정보 문제 대량의 좌표 데이터를 메모리 안에 압축해 저장하기 위해 사용하는 여러 기법 중 쿼드 트리(quad tree)란 것이 있습니다. 주어진 공간을 항상 4개로 분할해 재귀적

algospot.com

<풀이>

1. 쿼드 트리로 압축된 문자열을 입력받는다.

2. 입력받은 쿼드 트리를 상하로 뒤집은 쿼드 트리를 출력한다.

 

<해법>

1. 쿼드 트리를 상하로 뒤집는 방법

=> 쿼드 트리를 상하로 뒤집었을 경우, 쿼드 트리의 순서는 x(아래 왼쪽)(아래 오른쪽)(위 왼쪽)(위 오른쪽)이 됩니다. 따라서, 압축된 쿼드 트리를 복원할 필요 없이, 각 부분의 압축된 문자열을 알아낸 후 위 순서에 따라 재배치를 해주면 됩니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <string>
 
using namespace std;
 
string str;
int pos;
string answer;
 
string quadtree() {
 
    char cur = str[pos++];
 
    //b나 w일 경우 해당 부분 완료
    if (cur == 'b' || cur == 'w') {
        return string(1, cur);
    }
 
    //4부분 나눠서 해결
    string upLeft = quadtree();
    string upRight = quadtree();
    string downLeft = quadtree();
    string downRight = quadtree();
 
    //상하로 뒤집었을 때의 순서
    return "x" + downLeft + downRight + upLeft + upRight;
}
 
int main() {
 
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        str = "";
        pos = 0;
        answer = "";
 
        //입력
        cin >> str;
 
        //해법
        answer = quadtree();
 
        //출력
        cout << answer << "\n";
    }
 
    //종료
    return 0;
}
 

 

분할 정복에 대해 알아볼 수 있는 문제였습니다.


아래 문제를 응용한 것이 위 문제라고 생각합니다. 아래 문제도 풀어보는 것도 도움이 될 것 같습니다!

www.acmicpc.net/problem/1992

 

1992번: 쿼드트리

첫째 줄에는 영상의 크기를 나타내는 숫자 N 이 주어진다. N 은 언제나 2의 제곱수로 주어지며, 1 ≤ N ≤ 64의 범위를 가진다. 두 번째 줄부터는 길이 N의 문자열이 N개 들어온다. 각 문자열은 0 또

www.acmicpc.net

 

swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWHPkqBqAEsDFAUn&categoryId=AWHPkqBqAEsDFAUn&categoryType=CODE

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<풀이>

1. 문제의 배점들을 입력받는다.

2. 배점들로 만들 수 있는 점수의 가짓수를 출력한다.

 

<해법>

1. 점수의 가짓수를 계산하는 방법

=> 예를 들어서 설명해보겠습니다. 만약, 주어진 배점들로 만들 수 있는 점수가 0, 3, 5, 8, 10이고, 새로운 문제의 배점은 5점이라고 가정하겠습니다. 이 때, 만들 수 있는 새로운 점수는 기존에 가지고 있던 점수에 새로운 문제 배점을 더한 값들일 것입니다. 0+5, 3+5, 5+5, 8+5, 10+5 -> 5, 8, 10, 13, 15 입니다. 여기서 5, 8, 10은 중복된 값이므로 제외하면, 만들 수 있는 점수들은 0, 3, 5, 8, 10, 13, 15 입니다. 따라서, 기존에 만들 수 있는 점수들에 새로운 문제 배점들을 더해가면서 만들 수 있는 점수를 늘려갑니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <string.h>
#include <vector>
 
using namespace std;
 
int N;
int score[100];
bool visited[10001];
vector<int> canScore;
int answer;
 
int main() {
 
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        N = 0;
        memset(score, 0sizeof(score));
        memset(visited, false , sizeof(visited));
        canScore.clear();
        answer = 0;
 
        //입력
        cin >> N;
        for (int i = 0; i < N; i++) {
            cin >> score[i];
        }
 
        //해법
        //0점부터 시작
        canScore.push_back(0);
        visited[0= true;
 
        for (int i = 0; i < N; i++) {
            
            //현재 만들 수 있는 점수의 개수(벡터 사이즈) 저장
            int v_size = canScore.size();
 
            for (int j = 0; j < v_size; j++) {
 
                //새로운 점수 = 현재 만들 수 있는 점수 + 새로운 배점
                int newScore = canScore[j] + score[i];
 
                //이전에 만들 수 있는 점수가 아닌 경우 -> 벡터에 저장
                if (!visited[newScore]) {
                    canScore.push_back(newScore);
                    visited[newScore] = true;
                }
            }
        }
 
        //결과 갱신
        answer = canScore.size();
 
        //출력
        cout << "#" << test_case << " " << answer << "\n";
    }
 
    //종료
    return 0;
}
 

 

수학적인 사고에 대해 알아볼 수 있는 문제였습니다.


위 문제보다 조금 더 어렵지만, 같은 사고를 이용하여 푸는 문제입니다. 아래 문제도 풀어보시면 도움이 될 것 같습니다!

www.acmicpc.net/problem/2437

 

2437번: 저울

하나의 양팔 저울을 이용하여 물건의 무게를 측정하려고 한다. 이 저울의 양 팔의 끝에는 물건이나 추를 올려놓는 접시가 달려 있고, 양팔의 길이는 같다. 또한, 저울의 한쪽에는 저울추들만 놓

www.acmicpc.net

 

swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV7GOPPaAeMDFAXB&categoryId=AV7GOPPaAeMDFAXB&categoryType=CODE

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

<풀이>

1. 정점 개수와 간선 정보를 입력받는다.

2. 한 정점에서 다른 정점으로 갈 수 있는 최장 경로를 계산하여 출력한다.

 

<해법>

1. 최장 경로를 계산하는 방법

=> 어떤 정점에서 출발해야하는지 모르기 때문에, 모든 정점에서 출발해보아야 합니다. 따라서, 모든 정점에서 출발하여 겹치지 않고 갈 수 있는 정점까지 가서 최장경로를 계산합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <string.h>
 
using namespace std;
 
int N, M;
int edge[11][11];
bool visited[11];
int answer;
 
void findLongestPath(int index, int pathCount) {
 
    //결과 갱신
    if (pathCount > answer) {
        answer = pathCount;
    }
 
    //현재 정점에서 갈 수 있는 모든 정점 가보기
    for (int i = 1; i <= N; i++) {
 
        //간선이 있고, 이전에 방문한 적이 없는 경우 -> 방문
        if (edge[index][i] && !visited[i]) {
            visited[i] = true;
            findLongestPath(i, pathCount + 1);
            visited[i] = false;
        }
    }
}
 
int main() {
 
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        N = 0, M = 0;
        memset(edge, 0sizeof(edge));
        memset(visited, falsesizeof(visited));
        answer = 0;
 
        //입력
        cin >> N >> M;
        for (int i = 0; i < M; i++) {
            int x, y;
            cin >> x >> y;
            
            //간선 정보 등록
            edge[x][y] = 1;
            edge[y][x] = 1;
        }
 
        //해법
        /*
        1번 정점부터 N번 정점까지 모두 최장경로 찾기
        */
        for (int i = 1; i <= N; i++) {
            visited[i] = true;
            findLongestPath(i, 1);
            visited[i] = false;
        }
 
        //출력
        cout << "#" << test_case << " " << answer << "\n";
    }
 
    //종료
    return 0;
}
 

 

브루트포스에 대해 알아볼 수 있는 문제였습니다.

www.algospot.com/judge/problem/read/CLOCKSYNC

 

algospot.com :: CLOCKSYNC

Synchronizing Clocks 문제 정보 문제 그림과 같이 4 x 4 개의 격자 형태로 배치된 16개의 시계가 있다. 이 시계들은 모두 12시, 3시, 6시, 혹은 9시를 가리키고 있다. 이 시계들이 모두 12시를 가리키도록

www.algospot.com

<풀이>

1. 16개 시계를 입력받는다.

2. 각 버튼을 0~3번씩 누르는 모든 경우를 시뮬레이션 해본다.

3. 가장 적게 버튼을 누른 횟수를 출력한다.

 

<해법>

1. 모든 경우를 다 해보는 방법

=> 모든 경우를 다 해야하므로 브루트 포스를 사용해야 합니다. 그 이후 어떤 방식을 다 해봐야 할지 고민해봐야 합니다. 곰곰히 생각해보면, 중요한 것은 버튼을 누르는 순서가 아닌 횟수라는 것을 알 수 있습니다. 그 횟수 또한 0에서 최대 3번까지로 제한된다는 것을 알 수 있습니다.

따라서, 각 버튼을 눌러야하는 횟수를 저장한 후 모든 경우를 시뮬레이션 해보는 방식으로 구현하였습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <iostream>
#include <string>
#include <string.h>
 
using namespace std;
 
int clocks[16];
int playClocks[16];
string button[10= {
    "xxx............."//0번 버튼
    "...x...x.x.x...."//1번 버튼
    "....x.....x...xx"//2번 버튼
    "x...xxxx........"//...
    "......xxx.x.x...",
    "x.x...........xx",
    "...x..........xx",
    "....xx.x......xx",
    ".xxxxx..........",
    "...xxx...x...x.."
};
//0~9번 버튼을 몇 번 눌러야 하는지 저장하는 배열
int btnCnt[10];
int answer;
 
void makeClock(int index, int totalCount) {
 
    //정답보다 많은 스위치를 눌러야할 경우 -> 종료
    if (answer != -1 && answer <= totalCount) {
        return;
    }
 
    //종료 조건 : 10개의 버튼을 몇 번 눌러야할지 모두 정한 경우
    if (index == 10) {
 
        //시뮬레이션 위해 복사
        memcpy(playClocks, clocks, sizeof(playClocks));
 
        //시뮬레이션
        for (int i = 0; i < 10; i++) {
            int btn = i;
            int count = btnCnt[i];
 
            for (int j = 0; j < 16; j++) {
                if (button[btn][j] == 'x') {
                    playClocks[j] += 3 * count;
                }
            }
        }
 
        //모두 12시를 가르키는지 확인
        bool canAnswer = true;
        for (int i = 0; i < 16; i++) {
            if (playClocks[i] % 12 != 0) {
                canAnswer = false;
                break;
            }
        }
 
        //결과 갱신
        if (canAnswer) {
            if (answer == -1 || totalCount < answer) {
                answer = totalCount;
            }
        }
 
        return;
    }
 
    //0~3번 누르는 모든 경우 해보기
    for (int i = 0; i < 4; i++) {
        btnCnt[index] = i;
        makeClock(index + 1, totalCount + i);
    }
}
 
int main() {
 
    int test_case;
    int T;
 
    cin >> T;
 
    for (test_case = 1; test_case <= T; test_case++) {
 
        //초기화
        memset(clocks, 0sizeof(clocks));
        memset(btnCnt, 0sizeof(btnCnt));
        answer = -1;
 
        //입력
        for (int i = 0; i < 16; i++) {
            cin >> clocks[i];
        }
 
        //해법
        /*
        각 스위치마다 몇 번씩 눌러야 하는지 정하고,
        각 경우마다 모두 시뮬레이션
        */
        makeClock(00);
 
        //출력
        cout << answer << "\n";
    }
 
    //종료
    return 0;
}

 

브루트포스, 구현, 시뮬레이션에 대해 알아볼 수 있는 문제였습니다.

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

 

코딩테스트 연습 - [1차] 캐시

3 [Jeju, Pangyo, Seoul, NewYork, LA, Jeju, Pangyo, Seoul, NewYork, LA] 50 3 [Jeju, Pangyo, Seoul, Jeju, Pangyo, Seoul, Jeju, Pangyo, Seoul] 21 2 [Jeju, Pangyo, Seoul, NewYork, LA, SanFrancisco, Seoul, Rome, Paris, Jeju, NewYork, Rome] 60 5 [Jeju, Pangyo, S

programmers.co.kr

<풀이>

1. 각 도시이름을 캐시에 넣는다.

2. LRU 알고리즘에 따라, 캐시를 교체하고 실행시간을 갱신한다.

3. 총 실행시간을 반환한다.

 

<해법>

1. 캐시 구현 방법

=> 저는 deque를 이용하여 캐시를 구현하였습니다. 또한 가장 오래전에 사용된 값은 덱의 맨 앞에, 가장 최근에 사용된 값은 덱의 맨 뒤에 저장하였습니다. 덱을 사용한 이유는, 교체될 덱의 맨 앞의 값을 pop_front() 함수를 써서 쉽게 빼기 위함입니다.

 

2. 캐시 교체 방법

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <string>
#include <vector>
#include <deque>
 
using namespace std;
 
int solution(int cacheSize, vector<string> cities) {
 
    int answer = 0;
 
    //pop_front()를 사용하기 위해 deque를 사용
    deque<string> cache;
 
    for (int i = 0; i < cities.size(); i++) {
 
        //캐시에 넣어야 할 도시
        string city = cities[i];
 
        //대문자 -> 소문자 변환
        for (int j = 0; j < city.length(); j++) {
            city[j] = tolower(city[j]);
        }
 
        //캐시 hit, miss인지 판단
        bool hit = false;
        int index = 0;
        for (index = 0; index < cache.size(); index++) {
            if (cache[index] == city) {
                hit = true;
                break;
            }
        }
 
        //일단 cache 가장 뒤에 넣기(LRU 이므로)
        cache.push_back(city);
 
        //캐시 hit일 경우
        if (hit) {
            //캐시에 있는 기존 데이터 삭제
            cache.erase(cache.begin() + index);
            answer += 1;
        }
        //캐시 miss일 경우
        else {
            //캐시가 넘쳤을 경우, 맨 앞에 있는 가장 오래된 데이터 삭제
            if (cache.size() > cacheSize) {
                cache.pop_front();
            }
            answer += 5;
        }
    }
 
    //결과 반환
    return answer;
}
 

 

구현에 대해 알아볼 수 있는 문제였습니다.

www.acmicpc.net/problem/12100

 

12100번: 2048 (Easy)

첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2

www.acmicpc.net

<풀이>

1. 보드를 입력받는다.

2. 5번 움직일 수 있는 모든 경우에 따라, 가질 수 있는 최댓값들 중 최댓값을 구한다.

 

<해법>

1. 보드를 움직이는 방법

=> 블록은 2개씩만 합쳐질 수 있습니다. 따라서, 저는 비교하는 값과 비교당하는 값 이렇게 두 개를 나누어서 계산하였습니다. 그리고 만들어진 결과물을 큐에 옮겨 담고, 다시 그 큐의 값을 보드로 옮기는 방식으로 구현하였습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#include <iostream>
#include <string.h>
#include <queue>
#include <algorithm>
 
using namespace std;
 
int N;
int playMap[20][20];
int map[20][20];
int arr[5];
int answer;
 
//왼쪽으로 밀기
void swipeLeft() {
    for (int i = 0; i < N; i++) {
 
        //비교 대상(2개씩만 합쳐지므로)
        int compare = -1;
 
        //최종 줄
        queue<int> resLine;
 
        for (int j = 0; j < N; j++) {
 
            //빈 칸이 아니고,
            if (playMap[i][j] != 0) {
 
                //비교 대상이 없는 경우, 해당 지점이 비교 대상이 됨
                if (compare == -1) {
                    compare = playMap[i][j];
                }
                //비교 대상이 있을 경우,
                else {
                    //비교 대상과 해당 지점이 같은지 확인
                    if (playMap[i][j] == compare) {
 
                        //비교 대상과 같은 경우, 2배값 저장
                        resLine.push(compare * 2);
 
                        //비교 대상 초기화
                        compare = -1;
                    }
                    else {
 
                        //비교 대상과 다른 경우, 비교값 저장
                        resLine.push(compare);
 
                        //비교 대상은 다시 현 지점
                        compare = playMap[i][j];
                    }
                }
            }
        }
 
        //비교 대상이 아직 남아 있는 경우(끝 지점의 경우)
        if (compare != -1) {
            resLine.push(compare);
        }
 
        //줄 만들기
        for (int j = 0; j < N; j++) {
            if (!resLine.empty()) {
                playMap[i][j] = resLine.front();
                resLine.pop();
            }
            else {
                playMap[i][j] = 0;
            }
        }
    }
}
 
//오른쪽으로 밀기
void swipeRight() {
    for (int i = 0; i < N; i++) {
        int compare = -1;
        queue<int> resLine;
        for (int j = N - 1; j >= 0; j--) {
            if (playMap[i][j] != 0) {
                if (compare == -1) {
                    compare = playMap[i][j];
                }
                else {
                    if (playMap[i][j] == compare) {
                        resLine.push(compare * 2);
                        compare = -1;
                    }
                    else {
                        resLine.push(compare);
                        compare = playMap[i][j];
                    }
                }
            }
        }
        if (compare != -1) {
            resLine.push(compare);
        }
 
        for (int j = N - 1; j >= 0; j--) {
            if (!resLine.empty()) {
                int data = resLine.front();
                playMap[i][j] = data;
                resLine.pop();
            }
            else {
                playMap[i][j] = 0;
            }
        }
    }
}
 
//위쪽으로 밀기
void swipeUp() {
    for (int i = 0; i < N; i++) {
        int compare = -1;
        queue<int> resLine;
        for (int j = 0; j < N; j++) {
            if (playMap[j][i] != 0) {
                if (compare == -1) {
                    compare = playMap[j][i];
                }
                else {
                    if (playMap[j][i] == compare) {
                        resLine.push(compare * 2);
                        compare = -1;
                    }
                    else {
                        resLine.push(compare);
                        compare = playMap[j][i];
                    }
                }
            }
        }
        
        if (compare != -1) {
            resLine.push(compare);
        }
 
        for (int j = 0; j < N; j++) {
            if (!resLine.empty()) {
                playMap[j][i] = resLine.front();
                resLine.pop();
            }
            else {
                playMap[j][i] = 0;
            }
        }
    }
}
 
//아래쪽으로 밀기
void swipeDown() {
    for (int i = 0; i < N; i++) {
        int compare = -1;
        queue<int> resLine;
        for (int j = N - 1; j >= 0; j--) {
            if (playMap[j][i] != 0) {
                if (compare == -1) {
                    compare = playMap[j][i];
                }
                else {
                    if (playMap[j][i] == compare) {
                        resLine.push(compare * 2);
                        compare = -1;
                    }
                    else {
                        resLine.push(compare);
                        compare = playMap[j][i];
                    }
                }
            }
        }
 
        if (compare != -1) {
            resLine.push(compare);
        }
 
        for (int j = N - 1; j >= 0; j--) {
            if (!resLine.empty()) {
                playMap[j][i] = resLine.front();
                resLine.pop();
            }
            else {
                playMap[j][i] = 0;
            }
        }
    }
}
 
int findMaxFromPlayMap() {
    int res = -1;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (playMap[i][j] > res) {
                res = playMap[i][j];
            }
        }
    }
    return res;
}
 
void play(int playCount) {
 
    //종료조건 : 5번 움직였을 경우
    if (playCount == 5) {
 
        //playMap에 입력받은 map 복사
        memcpy(playMap, map, sizeof(playMap));
 
        //방향에 맞게 움직이기
        for (int i = 0; i < 5; i++) {
            switch (arr[i]) {
            case 0:
                swipeRight();
                break;
            case 1:
                swipeLeft();
                break;
            case 2:
                swipeUp();
                break;
            case 3:
                swipeDown();
                break;
            }
        }
 
        //결과 갱신
        answer = max(findMaxFromPlayMap(), answer);
 
        //종료
        return;
    }
 
    //4개 방향 모두 해보기
    for (int i = 0; i < 4; i++) {
        arr[playCount] = i;
        play(playCount + 1);
    }
}
 
int main() {
 
    //초기화
    answer = 0;
 
    //입력
    cin >> N;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cin >> map[i][j];
        }
    }
 
    //해법
    /*
    위, 아래, 오른쪽, 왼쪽을 5번 움직일 수 있는 경우를 모두 구하고
    직접 움직인후, 최대값을 갱신한다.
    */
    play(0);
 
    //출력
    cout << answer << "\n";
 
    //종료
    return 0;
}
 

 

구현, 시뮬레이션, 브루트포스에 대해 알아볼 수 있는 문제였습니다.

+ Recent posts