재현이는 주변을 살펴보던 중 체스판과 말을 이용해서 새로운 게임을 만들기로 했다. 새로운 게임은 크기가 N×N인 체스판에서 진행되고, 사용하는 말의 개수는 K개이다. 말은 원판모양이고, 하나의 말 위에 다른 말을 올릴 수 있다. 체스판의 각 칸은 흰색, 빨간색, 파란색 중 하나로 색칠되어있다.

게임은 체스판 위에 말 K개를 놓고 시작한다. 말은 1번부터 K번까지 번호가 매겨져 있고, 이동 방향도 미리 정해져 있다. 이동 방향은 위, 아래, 왼쪽, 오른쪽 4가지 중 하나이다.

턴 한 번은 1번 말부터 K번 말까지 순서대로 이동시키는 것이다. 한 말이 이동할 때 위에 올려져 있는 말도 함께 이동한다. 말의 이동 방향에 있는 칸에 따라서 말의 이동이 다르며 아래와 같다. 턴이 진행되던 중에 말이 4개 이상 쌓이는 순간 게임이 종료된다.

  • A번 말이 이동하려는 칸이
    • 흰색인 경우에는 그 칸으로 이동한다. 이동하려는 칸에 말이 이미 있는 경우에는 가장 위에 A번 말을 올려놓는다.
      • A번 말의 위에 다른 말이 있는 경우에는 A번 말과 위에 있는 모든 말이 이동한다.
      • 예를 들어, A, B, C로 쌓여있고, 이동하려는 칸에 D, E가 있는 경우에는 A번 말이 이동한 후에는 D, E, A, B, C가 된다.
    • 빨간색인 경우에는 이동한 후에 A번 말과 그 위에 있는 모든 말의 쌓여있는 순서를 반대로 바꾼다.
      • A, B, C가 이동하고, 이동하려는 칸에 말이 없는 경우에는 C, B, A가 된다.
      • A, D, F, G가 이동하고, 이동하려는 칸에 말이 E, C, B로 있는 경우에는 E, C, B, G, F, D, A가 된다.
    • 파란색인 경우에는 A번 말의 이동 방향을 반대로 하고 한 칸 이동한다. 방향을 반대로 바꾼 후에 이동하려는 칸이 파란색인 경우에는 이동하지 않고 가만히 있는다.
    • 체스판을 벗어나는 경우에는 파란색과 같은 경우이다.

다음은 크기가 4×4인 체스판 위에 말이 4개 있는 경우이다.

첫 번째 턴은 다음과 같이 진행된다.

두 번째 턴은 다음과 같이 진행된다.

체스판의 크기와 말의 위치, 이동 방향이 모두 주어졌을 때, 게임이 종료되는 턴의 번호를 구해보자.

입력

첫째 줄에 체스판의 크기 N, 말의 개수 K가 주어진다. 둘째 줄부터 N개의 줄에 체스판의 정보가 주어진다. 체스판의 정보는 정수로 이루어져 있고, 각 정수는 칸의 색을 의미한다. 0은 흰색, 1은 빨간색, 2는 파란색이다.

다음 K개의 줄에 말의 정보가 1번 말부터 순서대로 주어진다. 말의 정보는 세 개의 정수로 이루어져 있고, 순서대로 행, 열의 번호, 이동 방향이다. 행과 열의 번호는 1부터 시작하고, 이동 방향은 4보다 작거나 같은 자연수이고 1부터 순서대로 →, ←, ↑, ↓의 의미를 갖는다.

같은 칸에 말이 두 개 이상 있는 경우는 입력으로 주어지지 않는다.

출력

게임이 종료되는 턴의 번호를 출력한다. 그 값이 1,000보다 크거나 절대로 게임이 종료되지 않는 경우에는 -1을 출력한다.

제한

  • 4 ≤ N ≤ 12
  • 4 ≤ K ≤ 10

예제 입력 1

4 4
0 0 2 0
0 0 1 0
0 0 1 2
0 2 0 0
2 1 1
3 2 3
2 2 1
4 1 2

예제 출력 1

-1

예제 입력 2

4 4
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
1 1 1
1 2 1
1 3 1
1 4 1

예제 출력 2

1

예제 입력 3

4 4
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
1 1 1
1 2 1
1 3 1
2 4 3

예제 출력 3

1

예제 입력 4

4 4
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
1 1 1
1 2 1
1 3 1
3 3 3

예제 출력 4

2

예제 입력 5

6 10
0 1 2 0 1 1
1 2 0 1 1 0
2 1 0 1 1 0
1 0 1 1 0 2
2 0 1 2 0 1
0 2 1 0 2 1
1 1 1
2 2 2
3 3 4
4 4 1
5 5 3
6 6 2
1 6 3
6 1 2
2 4 3
4 2 1

예제 출력 5

7

 

 

풀이

생각보다 쉬운문제였다.(물론 뇌절해서 4번?인가틀림)

각자 이동 할 chess 피스가 있는 층을 계산하고 어찌저찌 옮기면되는 문제

파란색과 경계밖일때는 같은방식.

move_white는 다음과 같다.

이동 해야 할 chess가 있는 곳을 cal_floor를 통해서 계산, 그리고 그 위에있는 것을 모두 잘라 이동.

move_red도 비슷한 방식

이동 해야 할 chess가 있는 곳을 cal_floor를 통해서 계산, 그리고 그 위에있는 것을 스택에 넣어서 이동

blue인 경우와 벽인 경우는 

방향을 change 한 뒤에 next_x와 next_y의 위치를 다시 계산,red나 빈공간이면 move_white,red 함수 호출

전체 코드는 다음과 같다.

move_blue도 함수로 만들려 했지만 귀차니즘과 &로 인한 오류로 인해그냥 쳐박아버린..

이거 해결시 https://www.acmicpc.net/problem/17780 이것도 꽁자로 해결

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
#include <iostream>
#include <vector>
#include <deque>
#include <algorithm>
#include <stack>
#define MAX 12+1
using namespace std;
// Chess_piece 구조체
struct Chess_piece
{
    int x, y;
    int dir;
    int num;
};
// 맵 크기, 말 개수
int N, K;
// 방향 →, ←, ↑, ↓
int dx[5= { 00,0,-1,1 };
int dy[5= { 01,-1,0,0 };
// 0 1 2, 흰색 빨간색 파란색 MAP
int map_color[MAX][MAX];
// Chess_piece 정보 저장
Chess_piece Chess_MAP[MAX];
// 쌓인 모양
deque<int> MAP[MAX][MAX];
void print() {
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            cout << MAP[i][j].size() << " ";
        }
        cout << endl;
    }
}
int cal_floor(int& index, int& size_MAP, int& pre_x, int& pre_y) {
    for (int i = 0; i < size_MAP; i++)
        if (MAP[pre_x][pre_y][i] == Chess_MAP[index].num)
            return i;
}
void move_red(int& pre_x, int& pre_y, int& i, int& next_x, int& next_y) {
    int size_MAP = MAP[pre_x][pre_y].size();
    int floor = cal_floor(i, size_MAP, pre_x, pre_y);
    stack<int> temp;
    // 이동할 것들 저장
    for (int j = floor; j < size_MAP; j++) {
        temp.push(MAP[pre_x][pre_y][j]);
    }
    while (!temp.empty()) {
        MAP[pre_x][pre_y].pop_back();
        MAP[next_x][next_y].push_back(temp.top());
        Chess_MAP[temp.top()].x = next_x;
        Chess_MAP[temp.top()].y = next_y;
        temp.pop();
    }
}
void move_white(int& pre_x, int& pre_y, int& i, int& next_x, int& next_y) {
    int size_MAP = MAP[pre_x][pre_y].size();
    int floor = cal_floor(i, size_MAP, pre_x, pre_y);
    vector<int> temp;
    // 이동할 것들 저장
    for (int j = floor; j < size_MAP; j++)
        temp.push_back(MAP[pre_x][pre_y][j]);
    // 이동
    for (auto j : temp) {
        MAP[pre_x][pre_y].pop_back();
        MAP[next_x][next_y].push_back(j);
        Chess_MAP[j].x = next_x;
        Chess_MAP[j].y = next_y;
    }
}
 
void solve() {
    int count = 1;
    while (1) {
        if (count > 1000) {
            cout << -1 << endl;
            break;
        }
        for (int i = 1; i <= K; i++) {
            int pre_x = Chess_MAP[i].x;
            int pre_y = Chess_MAP[i].y;
            int next_x = pre_x + dx[Chess_MAP[i].dir];
            int next_y = pre_y + dy[Chess_MAP[i].dir];
            if (next_x >= 1 && next_x <= N && next_y >= 1 && next_y <= N) {
                if (map_color[next_x][next_y] == 0) {
                    move_white(pre_x, pre_y, i, next_x, next_y);
                }
                else if (map_color[next_x][next_y] == 1) {
                    move_red(pre_x, pre_y, i, next_x, next_y);
                }
                else if (map_color[next_x][next_y] == 2) {
                    if (Chess_MAP[i].dir == 1)
                        Chess_MAP[i].dir = 2;
                    else if (Chess_MAP[i].dir == 2)
                        Chess_MAP[i].dir = 1;
                    else if (Chess_MAP[i].dir == 3)
                        Chess_MAP[i].dir = 4;
                    else if (Chess_MAP[i].dir == 4)
                        Chess_MAP[i].dir = 3;
                    next_x = pre_x + dx[Chess_MAP[i].dir];
                    next_y = pre_y + dy[Chess_MAP[i].dir];
                    if (next_x >= 1 && next_x <= N && next_y >= 1 && next_y <= N) {
                        if (map_color[next_x][next_y] == 0) {
                            move_white(pre_x, pre_y, i, next_x, next_y);
                        }
                        else if (map_color[next_x][next_y] == 1) {
                            move_red(pre_x, pre_y, i, next_x, next_y);
                        }
                    }
                }
            }
            else {
                if (Chess_MAP[i].dir == 1)
                    Chess_MAP[i].dir = 2;
                else if (Chess_MAP[i].dir == 2)
                    Chess_MAP[i].dir = 1;
                else if (Chess_MAP[i].dir == 3)
                    Chess_MAP[i].dir = 4;
                else if (Chess_MAP[i].dir == 4)
                    Chess_MAP[i].dir = 3;
                next_x = pre_x + dx[Chess_MAP[i].dir];
                next_y = pre_y + dy[Chess_MAP[i].dir];
                if (next_x >= 1 && next_x <= N && next_y >= 1 && next_y <= N) {
                    if (map_color[next_x][next_y] == 0) {
                        move_white(pre_x, pre_y, i, next_x, next_y);
                    }
                    else if (map_color[next_x][next_y] == 1) {
                        move_red(pre_x, pre_y, i, next_x, next_y);
                    }
                }
            }
            for (int num_ = 1; num_ <= K; num_++) {
                if (MAP[Chess_MAP[num_].x][Chess_MAP[num_].y].size() >= 4) {
                    cout << count << endl;
                    return;
                }
            }
        }
        count++;
    }
}
void input() {
    cin >> N >> K;
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            cin >> map_color[i][j];
    for (int i = 1; i <= K; i++) {
        int x, y, dir;
        cin >> x >> y >> dir;
        Chess_MAP[i] = { x,y,dir,i };
        MAP[x][y].push_back(i);
    }
}
// init 함수
void init() {
    ios::sync_with_stdio(false);
    cin.tie(0);
}
int main() {
    init();
    input();
    solve();
}
cs

 

문제

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로로 이동하려 한다. 최단경로는 맵에서 가장 적은 개수의 칸을 지나는 경로를 말하는데, 이때 시작하는 칸과 끝나는 칸도 포함해서 센다.

만약에 이동하는 도중에 한 개의 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 한 개 까지 부수고 이동하여도 된다.

한 칸에서 이동할 수 있는 칸은 상하좌우로 인접한 칸이다.

맵이 주어졌을 때, 최단 경로를 구해 내는 프로그램을 작성하시오.

입력

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.

출력

첫째 줄에 최단 거리를 출력한다. 불가능할 때는 -1을 출력한다.

풀이

간단한 BFS인데 조건을 하나줘서 어려워 보이게 하는 문제.

정점을 x,y 파괴유무로 하고  q에 넣는다.

이때 벽이 나오고 만약이 부술 수 있다면 부수고, 아니면 안부순다.

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
#include <iostream>
#include <queue>
#define MAX 1000+1
using namespace std;
struct vertex {
    int x, y;
    bool fracture;
};
int N, M;
char MAP[MAX][MAX];
int check_count[MAX][MAX][2];
int dx[4= { 0,1,0,-1 };
int dy[4= { 1,0,-1,0 };
void BFS(int x,int y) {
    queue <vertex> q;
    check_count[x][y][0= 1;
    q.push({ x,y,false });
    while (!q.empty()) {
        vertex temp = q.front();
        q.pop();
        if (temp.x == N && temp.y == M) {
            cout << check_count[temp.x][temp.y][temp.fracture] << endl;
            return;
        }
        for (int i = 0; i < 4; i++) {
            int next_x = temp.x + dx[i];
            int next_y = temp.y + dy[i];
            if (next_x >= 1 && next_x <= N && next_y >= 1 && next_y <= M) {
                if (MAP[next_x][next_y] == '1' && temp.fracture == 0) {
                    check_count[next_x][next_y][1= check_count[temp.x][temp.y][0+ 1;
                    q.push({ next_x,next_y,true });
                }
                else if (MAP[next_x][next_y] == '0' && check_count[next_x][next_y][temp.fracture] == 0) {
                    check_count[next_x][next_y][temp.fracture] = check_count[temp.x][temp.y][temp.fracture] + 1;
                    q.push({ next_x,next_y,temp.fracture });
                }
            } 
        }
    }
 
    cout << -1 << endl;
}
void input() {
    cin >> N >> M;
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= M; j++)
            cin >> MAP[i][j];
}
void init() {
    ios::sync_with_stdio(false);
    cin.tie(0);
}
int main() {
    init();
    input();
    BFS(11);
}
cs

 

질문과 훈수는 환영

문제

캐슬 디펜스는 성을 향해 몰려오는 적을 잡는 턴 방식의 게임이다. 게임이 진행되는 곳은 크기가 N×M인 격자판으로 나타낼 수 있다. 격자판은 1×1 크기의 칸으로 나누어져 있고, 각 칸에 포함된 적의 수는 최대 하나이다. 격자판의 N번행의 바로 아래(N+1번 행)의 모든 칸에는 성이 있다.

성을 적에게서 지키기 위해 궁수 3명을 배치하려고 한다. 궁수는 성이 있는 칸에 배치할 수 있고, 하나의 칸에는 최대 1명의 궁수만 있을 수 있다. 각각의 턴마다 궁수는 적 하나를 공격할 수 있고, 모든 궁수는 동시에 공격한다. 궁수가 공격하는 적은 거리가 D이하인 적 중에서 가장 가까운 적이고, 그러한 적이 여럿일 경우에는 가장 왼쪽에 있는 적을 공격한다. 같은 적이 여러 궁수에게 공격당할 수 있다. 공격받은 적은 게임에서 제외된다. 궁수의 공격이 끝나면, 적이 이동한다. 적은 아래로 한 칸 이동하며, 성이 있는 칸으로 이동한 경우에는 게임에서 제외된다. 모든 적이 격자판에서 제외되면 게임이 끝난다. 

게임 설명에서 보다시피 궁수를 배치한 이후의 게임 진행은 정해져있다. 따라서, 이 게임은 궁수의 위치가 중요하다. 격자판의 상태가 주어졌을 때, 궁수의 공격으로 제거할 수 있는 적의 최대 수를 계산해보자.

격자판의 두 위치 (r1, c1), (r2, c2)의 거리는 |r1-r2| + |c1-c2|이다.

입력

첫째 줄에 격자판 행의 수 N, 열의 수 M, 궁수의 공격 거리 제한 D가 주어진다. 둘째 줄부터 N개의 줄에는 격자판의 상태가 주어진다. 0은 빈 칸, 1은 적이 있는 칸이다.

출력

첫째 줄에 궁수의 공격으로 제거할 수 있는 적의 최대 수를 출력한다.

제한

  • 3 ≤ N, M ≤ 15
  • 1 ≤ D ≤ 10

풀이

문제 대충 보고 풀었다가 개고생한문제..

쉬운줄 알고 했는데 1시간 걸렸네요

코드의 흐름은 다음과 같습니다

1. 조합을 solve 함수를 통해서 3개를 선택 합니다.

2.kill_enemy함수에서 조합 kill_count 와 remove_count를 선언, 하나는 죽이는거, 하나는 내려와서 성에 도달한 것

3.total_enemy == kill_count + remove_count 가 될떄까지 while로 반복한다.

4.find_enemy_and_killed함수는 bfs를 통해서 각자 죽여야 할 적을 선택

5.각자 vector에 넣어놓은 적을 sort하고 kill한다.(cmp는 거리가 가깝고, y가 작은)

6.map을 move함수 . 이동하는것을 구현하기 귀찮으므로, 
  5행이라고 하면 5행=4행 ,4행=3행, 3행=2행 .. 으로 하고 0행은 0으로 채운다. 반복하면 끄읕 

 

 

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
// 백준 17135 캐슬디펜스
#include <iostream>
#include <vector>
#include <deque>
#include <queue>
#include <utility>
#include <algorithm>
#define MAX 20
using namespace std;
// 순서대로 행, 열, 거리제한
int N, M, D;
deque<int> MAP[MAX];
deque<int> COPY_MAP[MAX];
vector<int> choose;
int dx[4= { 0,1,0,-1 };
int dy[4= { 1,0,-1,0 };
int max_res = 0;
int total_enemy = 0;
struct enemy {
    int x;
    int y;
    int dis;
};
bool cmp(const enemy& a, const enemy& b) {
    if (a.dis > b.dis) {
        return a.dis < b.dis;
    }
    else {
        return a.y < b.y;
    }
}
void move(int &remove_count) {
    for (int i = 0; i < M; i++) {
        if (COPY_MAP[N - 1][i] == 1) {
            remove_count++;
        }
    }
    for (int i = 0; i < N - 1; i++) {
        COPY_MAP[N - 1 - i] = COPY_MAP[N - 2 - i];
    }
    COPY_MAP[0].clear();
    for (int i = 0; i < M; i++) {
        COPY_MAP[0].push_back(0);
    }
}
void find_enemy_and_killed(int &kill_count) {
    vector<enemy> vec[3];
     for (int i = 0; i < 3; i++) {
        queue<pair<intint>> q;
        int check[MAX][MAX] = { 0 };
        q.push(make_pair(N - 1, choose[i]));
        check[N - 1][choose[i]] = 1;
        bool flag = false;
        while (!q.empty()) {
            int x = q.front().first;
            int y = q.front().second;
            q.pop();
            if (COPY_MAP[x][y] == 1) {
                enemy temp;
                temp.x = x;
                temp.y = y;
                temp.dis = check[x][y];
                vec[i].push_back(temp);
                flag = true;
            }
            if (check[x][y] == D) {
                continue;
            }
            if (flag == true) {
                continue;
            }
            for (int j = 0; j < 4; j++) {
                int next_x = x + dx[j];
                int next_y = y + dy[j];
                if (next_x >= 0 && next_y >= 0 && next_x <= N - 1 && next_y <= M - 1) {
                    if (check[next_x][next_y] == 0) {
                        check[next_x][next_y] = check[x][y] + 1;
                        q.push(make_pair(next_x, next_y));
                    }
                }
            }
        }
    }
    for (int i = 0; i < 3; i++) {
        if (vec[i].empty())
            continue;
        sort(vec[i].begin(), vec[i].end(), cmp);
        if (COPY_MAP[vec[i][0].x][vec[i][0].y] == 1) {
            kill_count++;
            COPY_MAP[vec[i][0].x][vec[i][0].y] = 0;
        }
    }
}
void kill_enemy() {
    int kill_count = 0;
    int remove_count = 0;
    for (int i = 0; i < N; i++)
        COPY_MAP[i] = MAP[i];
    while (total_enemy != kill_count + remove_count) {
        find_enemy_and_killed(kill_count);
        move(remove_count);
    }
    max_res = max(max_res, kill_count);
}
void solve(int index, int count) {
    if (count == 3) {
        kill_enemy();
        return;
    }
    if (index >= M ) return;
    choose.push_back(index);
    solve(index + 1, count + 1);
    choose.pop_back();
    solve(index + 1, count);
}
void input() {
    cin >> N >> M >> D;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            int temp = 0;
            cin >> temp;
            if (temp == 1) {
                total_enemy++;
            }
            MAP[i].push_back(temp);
        }
    }
}
void init() {
    ios::sync_with_stdio(false);
    cin.tie(0);
}
int main() {
    init();
    input();
    solve(00);
    cout << max_res << endl;
}
cs

질문과 훈수는 환영

문제

크기가 3×3인 배열 A가 있다. 배열의 인덱스는 1부터 시작한다. 1초가 지날때마다 배열에 연산이 적용된다.

  • R 연산: 배열 A의 모든 행에 대해서 정렬을 수행한다. 행의 개수 ≥ 열의 개수인 경우에 적용된다.
  • C 연산: 배열 A의 모든 열에 대해서 정렬을 수행한다. 행의 개수 < 열의 개수인 경우에 적용된다.

한 행 또는 열에 있는 수를 정렬하려면, 각각의 수가 몇 번 나왔는지 알아야 한다. 그 다음, 수의 등장 횟수가 커지는 순으로, 그러한 것이 여러가지면 수가 커지는 순으로 정렬한다. 그 다음에는 배열 A에 정렬된 결과를 다시 넣어야 한다. 정렬된 결과를 배열에 넣을 때는, 수와 등장 횟수를 모두 넣으며, 순서는 수가 먼저이다.

예를 들어, [3, 1, 1]에는 3이 1번, 1가 2번 등장한다. 따라서, 정렬된 결과는 [3, 1, 1, 2]가 된다. 다시 이 배열에는 3이 1번, 1이 2번, 2가 1번 등장한다. 다시 정렬하면 [2, 1, 3, 1, 1, 2]가 된다.

정렬된 결과를 배열에 다시 넣으면 행 또는 열의 크기가 달라질 수 있다. R 연산이 적용된 경우에는 가장 큰 행을 기준으로 모든 행의 크기가 변하고, C 연산이 적용된 경우에는 가장 큰 열을 기준으로 모든 열의 크기가 변한다. 행 또는 열의 크기가 커진 곳에는 0이 채워진다. 수를 정렬할 때 0은 무시해야 한다. 예를 들어, [3, 2, 0, 0]을 정렬한 결과는 [3, 2]를 정렬한 결과와 같다.

행 또는 열의 크기가 100을 넘어가는 경우에는 처음 100개를 제외한 나머지는 버린다.

배열 A에 들어있는 수와 r, c, k가 주어졌을 때, A[r][c]에 들어있는 값이 k가 되기 위한 최소 시간을 구해보자.

입력

첫째 줄에 r, c, k가 주어진다. (1 ≤ r, c, k ≤ 100)

둘째 줄부터 3개의 줄에 배열 A에 들어있는 수가 주어진다. 배열 A에 들어있는 수는 100보다 작거나 같은 자연수이다.

출력

A[r][c]에 들어있는 값이 k가 되기 위한 연산의 최소 시간을 출력한다. 100초가 지나도 A[r][c] = k가 되지 않으면 -1을 출력한다.

 

풀이

생각보다 index가 꼬여서 햇갈린문제

다음과 같이 했다

R연산의 경우

각 행마다 R연산을 실행  했으며, vector에 빈도 , 숫자 이 순서로 push_back해주었다.

각 숫자의 빈도를 counting 하고, vector에 push, sort를 하면 순서가 맞는다.

그리고는 arr에 전달하는 과정이다.

 

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
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int R, C, K;
int row_count = 3;
int col_count = 3;
int arr[200][200];
int num_count[101];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> R >> C >> K;
    for (int i = 1; i <= 3; i++
        for (int j = 1; j <= 3; j++
            cin >> arr[i][j];
    int time = 0;
    while (1) {
        if (time > 100) {
            cout << -1 << endl;
            return 0;
        }
        if (arr[R][C] == K) {
            cout << time << endl;
            return 0;
        }
        else if (row_count >= col_count) {
            // 연산 R
            int max_size = 0;
            for (int i = 1; i <= row_count; i++) {
                vector<pair<intint>> vec;
                memset(num_count, 0sizeof(num_count));
                for (int j = 1; j <= col_count; j++)
                    num_count[arr[i][j]]++;
                for (int j = 1; j <= 100; j++) {
                    if (num_count[j] == 0) {
                        continue;
                    }
                    vec.push_back(make_pair(num_count[j], j));
                }
                for (int j = 1; j <= col_count; j++)
                    arr[i][j] = 0;
                sort(vec.begin(), vec.end());
                int index = 1;
                for (auto j : vec) {
                    arr[i][index++= j.second;
                    arr[i][index++= j.first;
                    if (index > 100)
                        break;
                }
                index--;
                max_size = max(index, max_size);
            }
            col_count = max_size;
        }
        else if (row_count < col_count) {
            // 연산 C
            int max_size = 0;
            for (int j = 1; j <= col_count; j++) {
                vector<pair<intint>> vec;
                memset(num_count, 0sizeof(num_count));
                for (int i = 1; i <= row_count; i++)
                    num_count[arr[i][j]]++;
                for (int i = 1; i <= 100; i++) {
                    if (num_count[i] == 0) {
                        arr[i][j] = 0;
                        continue;
                    }
                    vec.push_back(make_pair(num_count[i], i));
                }
                for (int i = 1; i <= row_count; i++)
                    arr[i][j] = 0;
                sort(vec.begin(), vec.end());
                int index = 1;
                for (auto i : vec) {
                    arr[index++][j] = i.second;
                    arr[index++][j] = i.first;
                    if (index > 100)
                        break;
                }
                index--;
                max_size = max(index, max_size);
            }
            row_count = max_size;
        }
        time++;
    }
 
}
cs

문제

2048 게임은 4×4 크기의 보드에서 혼자 즐기는 재미있는 게임이다. 이 링크를 누르면 게임을 해볼 수 있다.

이 게임에서 한 번의 이동은 보드 위에 있는 전체 블록을 상하좌우 네 방향 중 하나로 이동시키는 것이다. 이때, 같은 값을 갖는 두 블록이 충돌하면 두 블록은 하나로 합쳐지게 된다. 한 번의 이동에서 이미 합쳐진 블록은 또 다른 블록과 다시 합쳐질 수 없다. (실제 게임에서는 이동을 한 번 할 때마다 블록이 추가되지만, 이 문제에서 블록이 추가되는 경우는 없다)

<그림 1> <그림 2> <그림 3>

<그림 1>의 경우에서 위로 블록을 이동시키면 <그림 2>의 상태가 된다. 여기서, 왼쪽으로 블록을 이동시키면 <그림 3>의 상태가 된다.

<그림 4> <그림 5> <그림 6> <그림 7>

<그림 4>의 상태에서 블록을 오른쪽으로 이동시키면 <그림 5>가 되고, 여기서 다시 위로 블록을 이동시키면 <그림 6>이 된다. 여기서 오른쪽으로 블록을 이동시켜 <그림 7>을 만들 수 있다.

<그림 8> <그림 9>

<그림 8>의 상태에서 왼쪽으로 블록을 옮기면 어떻게 될까? 2가 충돌하기 때문에, 4로 합쳐지게 되고 <그림 9>의 상태가 된다.

<그림 10> <그림 11> <그림 12> <그림 13>

<그림 10>에서 위로 블록을 이동시키면 <그림 11>의 상태가 된다. 

<그림 12>의 경우에 위로 블록을 이동시키면 <그림 13>의 상태가 되는데, 그 이유는 한 번의 이동에서 이미 합쳐진 블록은 또 합쳐질 수 없기 때문이다.

<그림 14> <그림 15>

마지막으로, 똑같은 수가 세 개가 있는 경우에는 이동하려고 하는 쪽의 칸이 먼저 합쳐진다. 예를 들어, 위로 이동시키는 경우에는 위쪽에 있는 블록이 먼저 합쳐지게 된다. <그림 14>의 경우에 위로 이동하면 <그림 15>를 만든다.

이 문제에서 다루는 2048 게임은 보드의 크기가 N×N 이다. 보드의 크기와 보드판의 블록 상태가 주어졌을 때, 최대 5번 이동해서 만들 수 있는 가장 큰 블록의 값을 구하는 프로그램을 작성하시오.

입력

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

출력

최대 5번 이동시켜서 얻을 수 있는 가장 큰 블록을 출력한다.

예제 입력 1

3
2 2 2
4 4 4
8 8 8

예제 출력 1

16

 

풀이

복잡한줄 알았지만 생각보다 쉬운문제.

시간또한 넉넉 4*4*4*4*4 이동방향을 모두 해봤자 1024개

이동하는 방향으로 이동하는 블럭의 순서를 쉽게 생각 할 수있다.

나는 이동하는 방향의 행 또는 열에서 이동순서에 맞게 queue에 넣어 해결했다.

위로 이동시 1행부터 ~ 5행까지 순서

아래로 이동시 5행부터 ~ 1행까지

오른쪽 이동시 5열부터 ~ 1열까지

왼쪽 이동시 1열부터 ~ 5열까지

코드는 다음과 같다.

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
// 백준 12100 2048(Easy)
#include <iostream>
#include <queue>
#define MAX 20+1
using namespace std;
// 보드 크기
int N;
// 위 오른쪽 아래 왼쪽
// 원래 맵
int choose_dir[5];
int map[MAX][MAX];
int copy_map[MAX][MAX];
int count_max = 0;
void move_block() {
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            copy_map[i][j] = map[i][j];
    queue<int> q;
    for (int k = 0; k < 5; k++) {
        if (choose_dir[k] == 0) {
            for (int j = 1; j <= N; j++) {
                int index = 1;
                for (int i = 1; i <= N; i++) {
                    if (copy_map[i][j] != 0) {
                        q.push(copy_map[i][j]);
                        copy_map[i][j] = 0;
                    }
                }
                while (!q.empty()) {
                    if (copy_map[index][j] == 0) {
                        copy_map[index][j] = q.front();
                        q.pop();
                        continue;
                    }
                    else if (copy_map[index][j] != q.front()) {
                        index++;
                        copy_map[index][j] = q.front();
                        q.pop();
                        continue;
                    }
                    else if (copy_map[index][j] == q.front()) {
                        copy_map[index][j] *= 2;
                        q.pop();
                        index++;
                    }
                }
            }
        }
        else if (choose_dir[k] == 1) {
            for (int i = 1; i <= N; i++) {
                int index = N;
                for (int j = N; j >= 1; j--) {
                    if (copy_map[i][j] != 0) {
                        q.push(copy_map[i][j]);
                        copy_map[i][j] = 0;
                    }
                }
                while (!q.empty()) {
                    if (copy_map[i][index] == 0) {
                        copy_map[i][index] = q.front();
                        q.pop();
                        continue;
                    }
                    else if (copy_map[i][index] != q.front()) {
                        index--;
                        copy_map[i][index] = q.front();
                        q.pop();
                        continue;
                    }
                    else if (copy_map[i][index] == q.front()) {
                        copy_map[i][index] *= 2;
                        q.pop();
                        index--;
                    }
                }
            }
        }
        else if (choose_dir[k] == 2) {
            for (int j = 1; j <= N; j++) {
                int index = N;
                for (int i = N; i >= 1; i--) {
                    if (copy_map[i][j] != 0) {
                        q.push(copy_map[i][j]);
                        copy_map[i][j] = 0;
                    }
                }
                while (!q.empty()) {
                    if (copy_map[index][j] == 0) {
                        copy_map[index][j] = q.front();
                        q.pop();
                        continue;
                    }
                    else if (copy_map[index][j] != q.front()) {
                        index--;
                        copy_map[index][j] = q.front();
                        q.pop();
                        continue;
                    }
                    else if (copy_map[index][j] == q.front()) {
                        copy_map[index][j] *= 2;
                        q.pop();
                        index--;
                    }
                }
            }
        }
        else if (choose_dir[k] == 3) {
            for (int i = 1; i <= N; i++) {
                int index = 1;
                for (int j = 1; j <= N; j++) {
                    if (copy_map[i][j] != 0) {
                        q.push(copy_map[i][j]);
                        copy_map[i][j] = 0;
                    }
                }
                while (!q.empty()) {
                    if (copy_map[i][index] == 0) {
                        copy_map[i][index] = q.front();
                        q.pop();
                        continue;
                    }
                    else if (copy_map[i][index] != q.front()) {
                        index++;
                        copy_map[i][index] = q.front();
                        q.pop();
                        continue;
                    }
                    else if (copy_map[i][index] == q.front()) {
                        copy_map[i][index] *= 2;
                        q.pop();
                        index++;
                    }
                }
            }
        }
 
    }
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            count_max = max(count_max, copy_map[i][j]);
}
void choose_five_dir(int count) {
    if (count == 5) {
        move_block();
        return;
    }
    for (int i = 0; i < 4; i++) {
        choose_dir[count] = i;
        choose_five_dir(count + 1);
    }
}
void input() {
    cin >> N;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            cin >> map[i][j];
        }
    }
}
void init() {
    ios::sync_with_stdio(false);
    cin.tie(0);
}
int main() {
    init();
    input();
    choose_five_dir(0);
    cout << count_max << endl;
}
 
cs

훈수와 질문은 언제나 환영

문제

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

파이어스톰을 시전하려면 시전할 때마다 단계 L을 결정해야 한다. 파이어스톰은 먼저 격자를 2L × 2L 크기의 부분 격자로 나눈다. 그 후, 모든 부분 격자를 시계 방향으로 90도 회전시킨다. 이후 얼음이 있는 칸 3개 또는 그 이상과 인접해있지 않은 칸은 얼음의 양이 1 줄어든다. (r, c)와 인접한 칸은 (r-1, c), (r+1, c), (r, c-1), (r, c+1)이다. 아래 그림의 칸에 적힌 정수는 칸을 구분하기 위해 적은 정수이다.

마법사 상어는 파이어스톰을 총 Q번 시전하려고 한다. 모든 파이어스톰을 시전한 후, 다음 2가지를 구해보자.

  1. 남아있는 얼음 A[r][c]의 합
  2. 남아있는 얼음 중 가장 큰 덩어리가 차지하는 칸의 개수

얼음이 있는 칸이 얼음이 있는 칸과 인접해 있으면, 두 칸을 연결되어 있다고 한다. 덩어리는 연결된 칸의 집합이다.

입력

첫째 줄에 N과 Q가 주어진다. 둘째 줄부터 2N개의 줄에는 격자의 각 칸에 있는 얼음의 양이 주어진다. r번째 줄에서 c번째 주어지는 정수는 A[r][c] 이다.

마지막 줄에는 마법사 상어가 시전한 단계 L1, L2, ..., LQ가 순서대로 주어진다.

 

풀이

처음에는 분할하여 하는 것을 생각하였지만 멍청한 생각이였다.

남아있는 얼음개수, 얼음 덩어리는 BFS로 간단하게 해결이 가능하지만, 움직이는걸 해결하는데 큰 시간이 걸렸다..

결론적으로 이동하는 규칙은 은근? 간단하였다.

L=1일때와 L=2일때 보면 행과 열에 따라 규칙을 가지고 이동하였다.

L에 따라 나눠진 조각을 보고 각장  1행,2행.. 1열,2열로 생각하면, 이동시 행은 열, 열은 2^l +1 -i 인 규칙을 가지고 

있다.

즉 이렇게 표현이 가능하다. 

행 -> 열, 열은 2^L + 1 -i, 주의 해야 하는 것은 나의 경우에는 temp_map에 저장 할 때 1,1로 그 나눠진 네모칸을 옮겨서 하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void rotate_map(int x, int y, int l) {
    int len = (1 << l);
    for (int i = 1; i <= len; i++) {
        for (int j = 1; j <= len; j++) {
 
            temp_map[j][len + 1 - i] = map[x + i - 1][y + j - 1];
        } 
    }
    for (int i = 1; i <= len; i++) {
        for (int j =1 ; j <= len; j++) {
            map[x+i-1][y+j-1= temp_map[i][j];
        }
    }
}
cs

이동만 해결하면 문제는 매우 쉽다. 전체코드는 다음과 같다.

 

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
// 마법사 상어와 파이어스톰
#include <iostream>
#include <cmath>
#include <queue>
#include <utility>
#include <cstring>
#define MAX 64+2
using namespace std;
int N, Q;
int map[MAX][MAX];
int count_ = 0;
int temp_map[MAX][MAX];
int check[MAX][MAX];
int dx[4= { 0,0,1,-1 };
int dy[4= { 1,-1,0,0 };
int max_res = 0;
void BFS(int x,int y) {
    check[x][y] = 1;
    queue<pair<intint>> q;
    q.push(make_pair(x, y));
    int count = 1;
    while (!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        for (int i = 0; i < 4; i++) {
            int next_x = x + dx[i];
            int next_y = y + dy[i];
            if (next_x >= 1 && next_x <= (1 << N) && next_y >= 1 && next_y <= (1 << N)) {
                if (map[next_x][next_y] != 0 && check[next_x][next_y] == -1) {
                    check[next_x][next_y] = 1;
                    q.push(make_pair(next_x, next_y));
                    count++;
                }
            }
        }
    }
    max_res = max(max_res, count);
}
void melt() {
    queue<pair<intint>> melt_space;
    for (int i = 1; i <= (1 << N); i++) {
        for (int j = 1; j <= (1 << N); j++) {
            int count = 0;
            if (map[i][j] == 0)
                continue;
            for (int k = 0; k < 4; k++) {
                int next_x = i + dx[k];
                int next_y = j + dy[k];
                if (map[next_x][next_y] <= 0) {
                    count++;
                }
            }
            if (count >= 2) {
                melt_space.push(make_pair(i, j));
            }
        }
    }
    while (!melt_space.empty()) {
        map[melt_space.front().first][melt_space.front().second]--;
        melt_space.pop();
    }
}
 
void rotate_map(int x, int y, int l) {
    int len = (1 << l);
    for (int i = 1; i <= len; i++) {
        for (int j = 1; j <= len; j++) {
 
            temp_map[j][len + 1 - i] = map[x + i - 1][y + j - 1];
        } 
    }
    for (int i = 1; i <= len; i++) {
        for (int j =1 ; j <= len; j++) {
            map[x+i-1][y+j-1= temp_map[i][j];
        }
    }
}
void init() {
    ios::sync_with_stdio(false);
    cin.tie(0);
}
void input() {
    cin >> N >> Q;
    for (int i = 1; i <= (1 << N); i++) {
        for (int j = 1; j <= (1 << N); j++) {
            cin >> map[i][j];
        }
    }
}
void solve() {
    for (int i = 0; i < Q; i++) {
        int L;
        cin >> L;
        for (int j = 1; j <= (1 << N); j = j + (1 << L)) {
            for (int k = 1; k <= (1 << N); k = k + (1 << L)) {
                rotate_map(j, k, L);
            }
        }
        melt();
    }
    int total_ans = 0;
    memset(check, -1sizeof(check));
    for (int i = 1; i <= (1 << N); i++) {
        for (int j = 1; j <= (1 << N); j++) {
            total_ans += map[i][j];
            if (check[i][j] == -1 && map[i][j] != 0) {
                BFS(i, j);
            }
        }
    }
    cout << total_ans << endl;
    cout << max_res << endl;
 
}
int main() {
    init();
    input();
    solve();
}
cs

훈수와 질문은 언제나 환영

문제

부동산 투자로 억대의 돈을 번 상도는 최근 N×N 크기의 땅을 구매했다. 상도는 손쉬운 땅 관리를 위해 땅을 1×1 크기의 칸으로 나누어 놓았다. 각각의 칸은 (r, c)로 나타내며, r은 가장 위에서부터 떨어진 칸의 개수, c는 가장 왼쪽으로부터 떨어진 칸의 개수이다. r과 c는 1부터 시작한다.

상도는 전자통신공학과 출신답게 땅의 양분을 조사하는 로봇 S2D2를 만들었다. S2D2는 1×1 크기의 칸에 들어있는 양분을 조사해 상도에게 전송하고, 모든 칸에 대해서 조사를 한다. 가장 처음에 양분은 모든 칸에 5만큼 들어있다.

매일 매일 넓은 땅을 보면서 뿌듯한 하루를 보내고 있던 어느 날 이런 생각이 들었다.

나무 재테크를 하자!

나무 재테크란 작은 묘목을 구매해 어느정도 키운 후 팔아서 수익을 얻는 재테크이다. 상도는 나무 재테크로 더 큰 돈을 벌기 위해 M개의 나무를 구매해 땅에 심었다. 같은 1×1 크기의 칸에 여러 개의 나무가 심어져 있을 수도 있다.

이 나무는 사계절을 보내며, 아래와 같은 과정을 반복한다.

봄에는 나무가 자신의 나이만큼 양분을 먹고, 나이가 1 증가한다. 각각의 나무는 나무가 있는 1×1 크기의 칸에 있는 양분만 먹을 수 있다. 하나의 칸에 여러 개의 나무가 있다면, 나이가 어린 나무부터 양분을 먹는다. 만약, 땅에 양분이 부족해 자신의 나이만큼 양분을 먹을 수 없는 나무는 양분을 먹지 못하고 즉시 죽는다.

여름에는 봄에 죽은 나무가 양분으로 변하게 된다. 각각의 죽은 나무마다 나이를 2로 나눈 값이 나무가 있던 칸에 양분으로 추가된다. 소수점 아래는 버린다.

가을에는 나무가 번식한다. 번식하는 나무는 나이가 5의 배수이어야 하며, 인접한 8개의 칸에 나이가 1인 나무가 생긴다. 어떤 칸 (r, c)와 인접한 칸은 (r-1, c-1), (r-1, c), (r-1, c+1), (r, c-1), (r, c+1), (r+1, c-1), (r+1, c), (r+1, c+1) 이다. 상도의 땅을 벗어나는 칸에는 나무가 생기지 않는다.

겨울에는 S2D2가 땅을 돌아다니면서 땅에 양분을 추가한다. 각 칸에 추가되는 양분의 양은 A[r][c]이고, 입력으로 주어진다.

K년이 지난 후 상도의 땅에 살아있는 나무의 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N, M, K가 주어진다.

둘째 줄부터 N개의 줄에 A배열의 값이 주어진다. r번째 줄의 c번째 값은 A[r][c]이다.

다음 M개의 줄에는 상도가 심은 나무의 정보를 나타내는 세 정수 x, y, z가 주어진다. 처음 두 개의 정수는 나무의 위치 (x, y)를 의미하고, 마지막 정수는 그 나무의 나이를 의미한다.

출력

첫째 줄에 K년이 지난 후 살아남은 나무의 수를 출력한다.

제한

  • 1 ≤ N ≤ 10
  • 1 ≤ M ≤ N2
  • 1 ≤ K ≤ 1,000
  • 1 ≤ A[r][c] ≤ 100
  • 1 ≤ 입력으로 주어지는 나무의 나이 ≤ 10
  • 입력으로 주어지는 나무의 위치는 모두 서로 다름

풀이

생각보다 까다로운 문제였다.

단순히 10x10 이라 시간이 0.3초라도 넉넉하다고 생각했다.

처음 풀이는 봄, 여름, 가을 ,겨울은 구현 하고,  봄에서 배열은 계속 sort해주는 방식으로 하였다.

하지만 시간초과가 떳다..

그래서 생각한게 원래 계속 존재하는 나무는 크기가 새로 들어온 나무들 보다 크다는 생각을 하게 되었고,

deque를 사용하여 앞에 계속 새로운 나무를 push_front해주는 방식으로 sort횟수를 맨 처음 한번으로 바꾸었다.

코드는 다음과 같다.

각각 봄 여름 가을 겨울 함수로 구현.

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
// 백준 16235 나무 재태크
#include <iostream>
#include <vector>
#include <algorithm>
#include <deque>
#define MAX 10+1
using namespace std;
struct Tree {
    int x, y, z;
};
bool cmp(const Tree& a, const Tree& b) {
    return a.z < b.z;
}
int A[MAX][MAX];
int N, M, K;
int nutrien_map[MAX][MAX];
//  7  0  1
//  6     2
//  5  4  3
int dx[8= { -1,-1,0,1,1,1,0,-1 };
int dy[8= { 0,1,1,1,0,-1,-1,-1 };
deque<Tree> Tree_map;
vector<Tree> dead_tree;
void spring() {
    deque<Tree> temp;
    for (auto index : Tree_map) {
        if (nutrien_map[index.x][index.y] >= index.z) {
            nutrien_map[index.x][index.y] -= index.z;
            index.z++;
            temp.push_back(index);
        }
        else
            dead_tree.push_back(index); 
    }
    Tree_map.clear();
    Tree_map = temp;
}
void summer() {
    // 죽은 나무 양분 분배
    for (auto index : dead_tree) 
        nutrien_map[index.x][index.y] += index.z / 2;
    dead_tree.clear();
}
void fall() {
    int size = Tree_map.size();
    deque<Tree> temp_Vec;
    for (int i = 0; i < size; i++) {
        if (Tree_map[i].z % 5 != 0) {
            continue;
        }
        int x = Tree_map[i].x;
        int y = Tree_map[i].y;
        for (int j = 0; j < 8; j++) {
            int next_x = x + dx[j];
            int next_y = y + dy[j];
            if (next_x >= 1 && next_x <= N && next_y >= 1 && next_y <= N) {
                Tree temp;
                temp.x = next_x; temp.y = next_y; temp.z = 1;
                temp_Vec.push_back(temp);
            }
        }
    }
    for (auto i : temp_Vec) 
        Tree_map.push_front(i);
}
void winter() {
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            nutrien_map[i][j] += A[i][j];
}
void input() {
    // N 행과 열, M 심은 나무 숫자, K년
    cin >> N >> M >> K;
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            cin >> A[i][j];
    for (int i = 1; i <= M; i++) {
        Tree temp;
        cin >> temp.x >> temp.y >> temp.z;
        Tree_map.push_back(temp);
    }
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            nutrien_map[i][j] = 5;
    sort(Tree_map.begin(), Tree_map.end(), cmp);
}
void solve() {
    for (int year = 1; year <= K; year++) {
        spring();
        summer();
        fall();
        winter();
    }
    cout << Tree_map.size() << endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    input();
    solve();
}
cs

훈수는 언제나 환영입니다.

문제

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다. 칸에는 상어가 최대 한 마리 들어있을 수 있다. 상어는 크기와 속도를 가지고 있다.

낚시왕은 처음에 1번 열의 한 칸 왼쪽에 있다. 다음은 1초 동안 일어나는 일이며, 아래 적힌 순서대로 일어난다. 낚시왕은 가장 오른쪽 열의 오른쪽 칸에 이동하면 이동을 멈춘다.

  1. 낚시왕이 오른쪽으로 한 칸 이동한다.
  2. 낚시왕이 있는 열에 있는 상어 중에서 땅과 제일 가까운 상어를 잡는다. 상어를 잡으면 격자판에서 잡은 상어가 사라진다.
  3. 상어가 이동한다.

상어는 입력으로 주어진 속도로 이동하고, 속도의 단위는 칸/초이다. 상어가 이동하려고 하는 칸이 격자판의 경계를 넘는 경우에는 방향을 반대로 바꿔서 속력을 유지한 채로 이동한다.

왼쪽 그림의 상태에서 1초가 지나면 오른쪽 상태가 된다. 상어가 보고 있는 방향이 속도의 방향, 왼쪽 아래에 적힌 정수는 속력이다. 왼쪽 위에 상어를 구분하기 위해 문자를 적었다.

상어가 이동을 마친 후에 한 칸에 상어가 두 마리 이상 있을 수 있다. 이때는 크기가 가장 큰 상어가 나머지 상어를 모두 잡아먹는다.

낚시왕이 상어 낚시를 하는 격자판의 상태가 주어졌을 때, 낚시왕이 잡은 상어 크기의 합을 구해보자.

입력

첫째 줄에 격자판의 크기 R, C와 상어의 수 M이 주어진다. (2 ≤ R, C ≤ 100, 0 ≤ M ≤ R×C)

둘째 줄부터 M개의 줄에 상어의 정보가 주어진다. 상어의 정보는 다섯 정수 r, c, s, d, z (1 ≤ r ≤ R, 1 ≤ c ≤ C, 0 ≤ s ≤ 1000, 1 ≤ d ≤ 4, 1 ≤ z ≤ 10000)로 이루어져 있다. (r, c)는 상어의 위치, s는 속력, d는 이동 방향, z는 크기이다. d가 1인 경우는 위, 2인 경우는 아래, 3인 경우는 오른쪽, 4인 경우는 왼쪽을 의미한다.

두 상어가 같은 크기를 갖는 경우는 없고, 하나의 칸에 둘 이상의 상어가 있는 경우는 없다.

출력

낚시왕이 잡은 상어 크기의 합을 출력한다.

풀이

문제를 이해하면 쉬운 문제이다.
두가지 과정으로 진행하였다.

1. 낚시왕이 이동하여 물고기를 잡는 catch_shark

2. shark가 이동하는 shark_move 함수

구현 자체는 어렵지 않다.

이 문제의 중점은 상어의 정보를 어떻게 저장할 것인가, 이동 한 거리를 어떻게 계산할 것인가 이다.

shark 구조체를 만들어, 구조체 2차원 vector를 사용 하였다.

이동은 2(R-1), 2(C-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
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
// 백준 낚시왕
// 17143
#include <iostream>
#include <utility>
#include <vector>
#include <algorithm>
#define MAX 100+1
using namespace std;
int R, C, M;
// shark 구조체
struct shark {
    int x, y;
    int speed;
    int dir;
    int size;
};
// 1,2,3,4
// 위 아래 오른쪽 왼쪽
int dx[5= { 0,-1,1,0,0 };
int dy[5= { 0,0,0,1,-1 };
int total_result = 0;
vector<shark> shark_map[MAX][MAX];
vector<shark> temp;
bool cmp(const shark& a, const shark& b) {
    return a.size > b.size;
}
void catch_shark(int number_land) {
    int i;
    for (i = 1; i <= R; i++) {
        if (shark_map[i][number_land].size() != 0) {
            total_result += shark_map[i][number_land][0].size;
            shark_map[i][number_land].clear();
            return;
        }
    }
    return;
}
void shark_move() {
    for (int i = 1; i <= R; i++) {
        for (int j = 1; j <= C; j++) {
            for (auto k : shark_map[i][j]) 
                temp.push_back(k);
            shark_map[i][j].clear();
        }
    }
    for (auto &shark_temp : temp) {
        if (shark_temp.dir <= 2) {
            for (int i = 1; i <= shark_temp.speed;i++) {
                if (shark_temp.x == 1)
                    shark_temp.dir = 2;
                else if (shark_temp.x == R)
                    shark_temp.dir = 1;
                shark_temp.x += dx[shark_temp.dir];
                shark_temp.y += dy[shark_temp.dir];
            }
            if (!shark_map[shark_temp.x][shark_temp.y].empty()) {
                if (shark_map[shark_temp.x][shark_temp.y][0].size < shark_temp.size) {
                    shark_map[shark_temp.x][shark_temp.y].clear();
                    shark_map[shark_temp.x][shark_temp.y].push_back(shark_temp);
                }
            }
            else
                shark_map[shark_temp.x][shark_temp.y].push_back(shark_temp);
        }
        else if (shark_temp.dir >= 3) {
            for (int i = 1; i <= shark_temp.speed; i++) {
                if (shark_temp.y == 1)
                    shark_temp.dir = 3;
                else if (shark_temp.y == C)
                    shark_temp.dir = 4;
                shark_temp.x += dx[shark_temp.dir];
                shark_temp.y += dy[shark_temp.dir];
            }
            if (!shark_map[shark_temp.x][shark_temp.y].empty()) {
                if (shark_map[shark_temp.x][shark_temp.y][0].size < shark_temp.size) {
                    shark_map[shark_temp.x][shark_temp.y].clear();
                    shark_map[shark_temp.x][shark_temp.y].push_back(shark_temp);
                }
            }
            else
                shark_map[shark_temp.x][shark_temp.y].push_back(shark_temp);
        }
    }
    temp.clear();
 
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> R >> C >> M;
    for (int i = 0; i < M; i++) {
        shark temp;
        cin >> temp.x >> temp.y >> temp.speed >> temp.dir >> temp.size;
        if (temp.dir <= 2) {
            temp.speed %= 2 * (R - 1);
        }
        else if (temp.dir >= 3) {
            temp.speed %= 2 * (C - 1);
        }
        shark_map[temp.x][temp.y].push_back(temp);
    }
    for (int i = 1; i <= C; i++) {
        /*
        for (int i = 1; i <= R; i++) {
            for (int j = 1; j <= C; j++) {
                cout << shark_map[i][j].size();
            }
            cout << endl;
        }*/
        //cout << endl;
        catch_shark(i);
        shark_move();
        //cout << endl;
    }
    cout << total_result << endl;
}
cs

 

/

+ Recent posts