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

 

17144번: 미세먼지 안녕!

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사과는 뛰어난 코딩 실력을 이용해 각 칸 (r, c)에 있는 미세먼지의 양을 실시간으로 모니터링하는 시스템을 개발했다. (r, c)는 r행 c열을 의미한다. 공기청정기는 항상 왼쪽 열에 설치되어 있고, 크기는 두 행을 차지한다. 공기청정기가 설치되어 있지 않은 칸에는 미세먼

www.acmicpc.net

처음에 큐를 사용하지 않고 벡터로 구현을 했어서 헤맸던 문제였다...

공기청정기 바람 나오는 거 구현할 때에도 범위 때문에 계속 헷갈렸었다

공기청정기는 위쪽과 아래쪽을 나눠서 각각 구현해줬다. 그냥 문제에서 시키는 대로 한 칸씩 이동시켜주면 된다.

 

미세먼지 확산의 경우에는 확산되는 먼지는 따로 저장해서 나중에 한번에 더해줘야 한다.

바로 더해주면 확산된 곳에서 같은 시간에 다시 확산될 수 도 있기 때문이다

이 부분이랑 공기청정기에서 바람 나와서 이동할 때 범위만 조심해주면 될 것 같다!

 

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
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
 
int R, C, T;
int map[50][50];
int sum[50][50];
int air[2];
 
int dx[] = { 0,-1,0,1 };
int dy[] = { 1,0,-1,0 };
 
void goUpair() {
    int x, y;
    x = air[0- 1;
    y = 0;
 
    if (x < 0return;
 
    while (x > 0) {
        map[x][y] = map[x - 1][y];
        x--;
    }
    while (y < C - 1) {
        map[x][y] = map[x][y + 1];
        y++;
    }
    while (x < air[0]) {
        map[x][y] = map[x + 1][y];
        x++;
    }
    while (y > 1) {
        map[x][y] = map[x][y - 1];
        y--;
    }
    map[x][1= 0;
 
}
 
void goDownair() {
    int x, y;
    x = air[1+ 1;
    y = 0;
 
    if (x >= R) return;
 
    while (x < R - 1) {
        map[x][y] = map[x + 1][y];
        x++;
    }
    while (y < C - 1) {
        map[x][y] = map[x][y + 1];
        y++;
    }
    while (x > air[1]) {
        map[x][y] = map[x - 1][y];
        x--;
    }
    while (y > 1) {
        map[x][y] = map[x][y - 1];
        y--;
    }
    map[x][1= 0;
}
 
void spread() {
    queue<pair<intint>> q;
 
    //먼지가 있는 곳을 모두 큐에 넣어준다.
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            if (map[i][j] > 0) {
                q.push(make_pair(i, j));
            }
        }
    }
 
 
    int x, y;
    while (!q.empty()) {
        x = q.front().first;
        y = q.front().second;
        q.pop();
        int amt = map[x][y] / 5;
 
        for (int k = 0; k < 4; k++) {
            int nx = x + dx[k];
            int ny = y + dy[k];
            if (nx < 0 || ny < 0 || nx >= R || ny >= C) continue;
            if (map[nx][ny] == -1continue;
 
            //확산될때 원래자리에서는 빼주고
            //확산될 자리에서는 더해준다.
            map[x][y] -= amt;
            sum[nx][ny] += amt;
        }
    }
 
    //확산된 먼지들을 더해준다.
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            map[i][j] += sum[i][j];
        }
    }
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> R >> C >> T;
 
    bool flag = true;
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            cin >> map[i][j];
            if (map[i][j] == -1) {
                if (flag) {
                    //첫번째 공기청정기
                    air[0= i;
                    flag = false;
                }
                else {
                    //두번째 공기청정기
                    air[1= i;
                }
            }
        }
    }
 
 
    //T초 동안 확산과 공기청정(위쪽, 아래쪽)을 반복
    for (int i = 0; i < T; i++) {
        memset(sum, 0sizeof(sum));
        spread();
        goUpair();
        goDownair();
    }
 
 
    //남아있는 먼지 수를 계산
    int ans = 0;
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            ans += map[i][j];
        }
    }
 
 
    //공기청정기 2개때문에 빠진 값을 다시 더해준다.
    cout << ans + 2 << '\n';
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 17135. 캐슬 디펜스  (0) 2019.08.01
[BOJ] 16236. 아기 상어  (0) 2019.07.31
[BOJ] 17140. 이차원 배열과 연산  (0) 2019.07.30
[BOJ] 17142. 연구소 3  (0) 2019.07.30
[BOJ] 1806. 부분합  (0) 2019.07.16

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

 

17140번: 이차원 배열과 연산

첫째 줄에 r, c, k가 주어진다. (1 ≤ r, c, k ≤ 100) 둘째 줄부터 3개의 줄에 배열 A에 들어있는 수가 주어진다. 배열 A에 들어있는 수는 100보다 작거나 같은 자연수이다.

www.acmicpc.net

초기 배열의 크기가 3X3이고 1초가 지날 때마다 배열에 연산이 적용되는데

최종적으로 배열의 r행c열에 들어있는 값이 k가 되는 시간을 찾는 문제이다.

시간이 100을 넘어가는 경우에는 -1을 출력한다.

 

R연산과 C연산은 다음과 같다.

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

 

이 문제에서 중요한 부분은 각 숫자의 등장 횟수를 센다음에 어떻게 새로 저장해 주느냐인 것 같다.

나는 벡터를 이용해서 저장했다. 벡터의 자료 형을 pair로 넣고 정렬할 경우

pair 중 앞부분 우선으로 먼저 정렬되고 그다음에 두 번째 걸로 정렬되는 점을 이용했다.

 

이 문제에서는 먼저 수의 등장 횟수순으로 정렬되어야 하기 때문에 등장 횟수를 앞에 넣어주고 수를

뒤에 넣어주었다. 그리고 다시 배열에 저장할때는 벡터의 뒤에 거를 먼저 빼서 넣어주고 앞에 거를 넣어줬다.

 

그리고 또 중요한 것은 바뀌는 행의 크기와 열의 크기이다.

매번 연산때마다 크기는 줄어들거나 커질 수 있는데 해당 연산에서의 최댓값으로 다시 갱신해주어야 한다.

 

 

자세한 설명은 코드의 R연산(rcalc) 부분을 참고!

C연산은 R연산을 열 기준으로 바꿔주면 되므로 생략했다.

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
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
 
int map[150][150];
int cnt[101];
int r, c, k;
int rsize, csize;
vector<pair<intint>> vt;
 
void c_calc() {
    int new_rsize = 0;
    for (int i = 0; i < csize; i++) {
 
        for (int j = 0; j < rsize; j++) {
            cnt[map[j][i]]++;
        }
 
        for (int k = 1; k <= 100; k++) {
            if (cnt[k] != 0) {
                vt.push_back(make_pair(cnt[k], k));
                cnt[k] = 0;
            }
        }
 
        sort(vt.begin(), vt.end());
 
 
        int vtsize = vt.size();
        int newsize = vtsize * 2;
        new_rsize = max(new_rsize, newsize);
        int index = 0;
        for (int k = 0; k < newsize; k += 2) {
            map[k][i] = vt.at(index).second;
            map[k + 1][i] = vt.at(index).first;
            index++;
        }
 
        for (int k = newsize; k < rsize; k++) {
            map[k][i] = 0;
        }
 
 
        vt.clear();
    }
 
    rsize = new_rsize;
}
 
 
void rcalc() {
 
    int new_csize = 0; //이번 연산에서 새로 바뀔 열 크기 중 최댓값이 저장된다.
 
    //모든 행에 대해서 R연산을 해준다.
    for (int i = 0; i < rsize; i++) {
 
        //숫자의 등장 횟수를 세기 위해서, 각 열의 숫자를 인덱스로 cnt배열의 값을 증가시킨다.
        for (int j = 0; j < csize; j++) {
            cnt[map[i][j]]++;
        }
 
 
        //개수가 0개가 아니라면 벡터에 넣어주고 cnt배열은 다시 0으로 초기화 해준다.
        for (int k = 1; k <= 100; k++) {
            if (cnt[k] != 0) {
 
                //수의 등장횟수로 먼저 정렬되므로 수의 등장횟수를 앞에 넣어주고
                //해당 수를 뒤에 넣어준다.
                vt.push_back(make_pair(cnt[k], k));
                cnt[k] = 0;
            }
        }
 
 
        //정렬
        sort(vt.begin(), vt.end());
 
 
        //쌍으로 벡터에 들어가있으므로 하나씩 꺼내주기 위해 2를 곱해준다.
        int vtsize = vt.size();
        int newsize = vtsize * 2;
 
        //현재 연산의 최대 열 길이(new_csize가 이번 연산이 끝나면 csize(열 사이즈)로 바뀐다)
        new_csize = max(new_csize, newsize);
 
 
        //map에 다시 넣어준다.
        int index = 0;
        for (int k = 0; k < newsize; k += 2) {
            //수를 뒤에 넣었으므로 두번째 값(second)을 먼저 꺼낸다.
            map[i][k] = vt.at(index).second;
 
            //수의 등장 횟수를 앞(first)에 넣어놨으므로 나중에 꺼낸다. 
            map[i][k + 1= vt.at(index).first;
            index++;
        }
 
        //숫자를 채우고 남은 칸을 0으로 채워준다. (열 크기까지)
        for (int k = newsize; k < csize; k++) {
            map[i][k] = 0;
        }
 
 
        //벡터 정리
        vt.clear();
    }
 
    //열 크기는 이번 연산에서 가장 긴 열의 크기로 바뀐다
    //(줄어들 수 도 있고 늘어날 수 도 있음)
    csize = new_csize;
 
}
 
 
void solve() {
    int time = 0;
    while (true) {
 
        //찾은 경우
        if (map[r][c] == k) {
            cout << time << '\n';
            break;
        }
 
        time++;
 
        //시간이 100을 넘어가는 경우
        if (time > 100) {
            cout << -1 << '\n';
            break;
        }
 
        //R연산
        if (rsize >= csize) {
            rcalc();
        }
        else {//C연산
            c_calc();
        }
    }
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> r >> c >> k;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            cin >> map[i][j];
        }
    }
 
    //index가 0번부터 시작하므로 1씩 빼준다.
    r--;
    c--;
 
    rsize = 3;
    csize = 3;
 
    solve();
 
    return 0;
}
Colored by Color Scripter
 

 

'BOJ' 카테고리의 다른 글

[BOJ] 16236. 아기 상어  (0) 2019.07.31
[BOJ] 17144. 미세먼지 안녕!  (0) 2019.07.30
[BOJ] 17142. 연구소 3  (0) 2019.07.30
[BOJ] 1806. 부분합  (0) 2019.07.16
[BOJ] 2003. 수들의 합 2  (0) 2019.07.15

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

 

17142번: 연구소 3

인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고, 활성 상태인 바이러스는 상하좌우로 인접한 모든 빈 칸으로 동시에 복제되며, 1초가 걸린다. 승원이는 연구소의 바이러스 M개를 활성 상태로 변경하려고 한다. 연구소는 크기가 N×N인 정사각형으로 나타낼 수 있으며, 정사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는

www.acmicpc.net

주어진 배열에 있는 바이러스들 중 m개를 골라 활성화시켜서 연구소에 퍼뜨리는 문제이다.

m개를 고르는 모든 경우를 해보고, 골랐을 때마다 bfs로 바이러스를 퍼뜨려서

모두 퍼뜨리는데 걸리는 최소시간을 구하면 된다. 즉 완전 탐색 + bfs 문제이다.

 

이 문제에서 주의 할점은 처음에 활성화하지 않은 바이러스들이다.

이 바이러스들은 애초에 퍼져있는 상태나 마찬가지이므로 이 위치는 0초에 퍼져있는 상태나 마찬가지이다.

그래서 처음에 시간을 0으로 처리해줬다가 bfs부분에서 넘어가 버려서 다음과 같은 테스트 케이스에서 -1이 나왔다.

(원래 정답은 2가 나와야 함)

 

4 2

0110

2112

2112

0110

 

활성화하지 않은 바이러스를 벽처럼 여겨서 넘어가지 못했기 때문이다.

그래서 일단 얘네들도 빈칸처럼 똑같이 처리해줬다.

그리고 마지막에 모두 퍼뜨리는데 걸리는 시간을 구할 때 좌표의 값이 2라면(바이러스였다면) 최대 시간으로 간주하지 않는다.

밑의 코드에서는 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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
 
int n, m;
int map[50][50];
int time[50][50];
int ans;
vector<pair<intint>> virus;
vector<pair<intint>> alive;
 
int dx[] = { 0,0,1,-1 };
int dy[] = { 1,-1,0,0 };
 
int check() {
    int maxtime = 0;
 
    //모든 칸을 검사
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
 
            //처음에 활성화하지 않은 바이러스의 시간을 최대값으로 저장하면 안되므로
            //현재 칸이 원래 빈칸이었고(바이러스가 아니고)
            // 최대시간보다 더 긴 시간을 가지고 있으면 최대시간으로 저장
            if (map[i][j] == 0 && maxtime < time[i][j]) {
                maxtime = time[i][j];
            }
 
            //빈칸인데 시간이 저장되어 있지 않다(바이러스가 퍼지지 못했다)
            if (map[i][j] == 0 && time[i][j] == -1) {
                return -1;
            }
        }
    }
 
    //모두 걸리는데 걸리는 시간을 리턴
    return maxtime;
}
 
void bfs() {
    memset(time, -1sizeof(time));
    queue<pair<intint>> q;
    int x, y;
 
 
    //활성 바이러스들을 큐에 넣어준다.
    for (int i = 0; i < m; i++) {
        x = alive.at(i).first;
        y = alive.at(i).second;
        q.push(make_pair(x, y));
        time[x][y] = 0;
    }
 
 
    int nx, ny;
    while (!q.empty()) {
        x = q.front().first;
        y = q.front().second;
        q.pop();
 
        //인접한 네방향으로 퍼진다.
        for (int k = 0; k < 4; k++) {
            nx = x + dx[k];
            ny = y + dy[k];
 
            //범위 체크
            if (nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
 
            //벽인 경우
            if (map[nx][ny] == 1continue;
 
            //빈 칸에 이미 방문
            if (time[nx][ny] != -1continue;
 
            q.push(make_pair(nx, ny));
            time[nx][ny] = time[x][y] + 1;
        }
 
    }
 
    //check함수로 모두 퍼질 수 없는 경우인 경우 -1, 그렇지 않은 경우 모두 퍼지는데
    //걸리는 시간을 받아온다.
    int tmp = check();
 
    if (tmp == -1) {
        //초기값이라면 -1을 그대로 넣어준다.
        if (ans == 10000000) {
            ans = -1;
        }
    }
    else {
        //받아온 시간이 최솟값이라면 ans에 저장
        //ans가 -1인 경우에도 새로 받아온 값(가능한 경우)로 바꿔줄 수 있다.
        if (ans == -1 || ans > tmp) {
            ans = tmp;
        }
    }
 
 
}
 
 
//활성화 시킬 바이러스 m개를 고른다.
void select(int index, int cnt) {
 
    //m개를 고른 경우
    if (cnt == m) {
        //바이러스를 활성화 시킨다.
        bfs();
        return;
    }
 
    //고를 수 있는 경우를 모두 넘어간 경우 리턴
    if (index >= virus.size()) return;
 
 
    //index번째 바이러스의 좌표를 가져온다.
    int x = virus.at(index).first;
    int y = virus.at(index).second;
 
 
    //index번째 바이러스를 선택한다.
    alive.push_back(make_pair(x, y));
    select(index + 1, cnt + 1);
 
 
    //index번째 바이러스를 선택하지 않는 경우
    alive.pop_back(); //선택하는 경우에서 넣은 거 뺀다
    select(index + 1, cnt);
 
}
 
 
 
int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> map[i][j];
 
            //바이러스인 경우 벡터에 좌표를 저장
            if (map[i][j] == 2) virus.push_back(make_pair(i, j));
        }
    }
 
    //최솟값을 찾기 위해서 큰 값을 넣어둔다.
    ans = 10000000;
    select(00);
 
    cout << ans << '\n';
 
    //선택하지 않은 바이러스 부분에도 시간 넣어줘야한다!!!!
 
 
    return 0;
}
Colored by Color Scripter
 
 
 

 

 

'BOJ' 카테고리의 다른 글

[BOJ] 17144. 미세먼지 안녕!  (0) 2019.07.30
[BOJ] 17140. 이차원 배열과 연산  (0) 2019.07.30
[BOJ] 1806. 부분합  (0) 2019.07.16
[BOJ] 2003. 수들의 합 2  (0) 2019.07.15
[BOJ] 2748. 피보나치 수 2  (0) 2019.07.15

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWIeV9sKkcoDFAVH

 

SW Expert Academy

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

www.swexpertacademy.com

자석들이 회전할 방향을 미리 저장해놓고 풀면 쉽게 풀 수 있는 문제이다.

회전시킬 자석의 왼편과 오른편 자석들을 모두 회전할지 안 할지 검사한다.

회전을 하게 된다면 옆에 있는 자석의 반대방향으로 회전한다.

 

오른편의 자석들을 검사할 때는 순차적으로 왼쪽 자석의 2번 날과 오른쪽 자석의 6번 날을 비교하여

다를 경우에 오른쪽 자석의 회전 방향을 왼쪽 자석의 회전방향의 반대방향으로 저장한다.

마찬가지로 왼편 자석들을 검사할떄도 왼쪽 자석의 2번 날과 오른쪽 자석의 6번 날을 비교하여

회전 방향을 저장한다. 

날의 자성이 같아서 회전하지 않을 경우에는 그 앞의 자석들도 회전하지 않으므로 검사를 중단한다.

 

회전 방향을 모두 저장해줬다면 이제 모든 자석들을 회전시킨다.

1이면 시계방향 -1이면 반시계방향으로 회전시켜준다.

0인 경우(회전하지 않는 경우)도 있으므로 조건 처리를 정확히 해주어야 한다.

 

회전까지 모두 마쳤다면 점수를 계산해준다.

문제에서의 화살표 방향은 각 자석의 0번째 날이므로 자석들의 0번째 날이 S극인지(1 인지) 확인하여 계산해주면 된다.

점수는 각각 1, 2, 4, 8로 2의 제곱수로 더해지므로 << 연산으로 쉽게 더해줄 수 있다.

( 1<< 0 은 1이므로 1점 /  1<<1 은 10(2진수)으로 2점 / 1<<2는 100(2진수)으로 4점 / 1<< 3 은 1000(2진수)으로 8점)

 

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
#include <iostream>
using namespace std;
 
int magnet[4][8];
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int T;
    cin >> T;
    for (int tc = 1; tc <= T; tc++) {
 
        int k;
        cin >> k;
 
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 8; j++) {
                cin >> magnet[i][j];
            }
        }
 
        while (k-- > 0) {
            int num;
            int dir;
            cin >> num >> dir;
            num -= 1;
 
 
            int dirArr[4= {0,};
            dirArr[num] = dir;
 
 
            //오른쪽 자석 검사
            for (int i = num; i < 3; i++) {
                if (magnet[i][2!= magnet[i+ 1][6]) {
                    dirArr[i + 1= dirArr[i] * -1;
                }
                else {
                    break;
                }
            }
 
 
            //왼쪽 자석 검사
            for (int i = num; i > 0; i--) {
                if (magnet[i][6!= magnet[i - 1][2]) {
                    dirArr[i - 1= dirArr[i] * -1;
                }
                else {
                    break;
                }
            }
 
 
            //회전
            for (int i = 0; i < 4; i++) {
 
                //시계방향 회전
                if (dirArr[i] == 1) {
                    int tmp = magnet[i][7];
                    for (int j = 7; j > 0; j--) {
                        magnet[i][j] = magnet[i][j - 1];
                    }
                    magnet[i][0= tmp;
                }//반시계방향 회전
                else if (dirArr[i] == -1) {
                    int tmp = magnet[i][0];
                    for (int j = 0; j < 7; j++) {
                        magnet[i][j] = magnet[i][j + 1];
                    }
                    magnet[i][7= tmp;
                }
            }
 
        }
 
 
        //점수 계산
        int ans = 0;
        for (int i = 0; i < 4; i++) {
            if (magnet[i][0== 1) {
                ans += (1 << i);
            }
        }
 
        cout << '#' << tc << ' ' << ans << '\n';
 
    }
 
    return 0;
}
Colored by Color Scripter
 

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5VwAr6APYDFAWu

 

SW Expert Academy

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

www.swexpertacademy.com

출발할 수 있는 모든 칸에서부터 출발하여  대각선 방향으로 움직이고 사각형 모양을 그리며 출발한 카페로 돌아온다.

n-1행, n-2행, 0열, n-1열인 곳에서는 사각형을 만들 수 없으므로 출발할 수 없다.

 

각 칸에서 출발하면 오른쪽아래(1,1), 왼쪽 아래(1,-1), 왼쪽 위(-1,-1), 오른쪽 위(-1,1)의 순서로 사각형을 그리도록 했다.

시작점인 경우에만 현재 방향을 유지해서 진행하고 그렇지 않은 경우에는

방향을 꺾어서 이동하는 경우와 현재 방향을 유지한채로 이동하는 경우를 모두 탐색했다.

 

같은 종류의 디저트를 먹으면 안되므로 디저트의 종류를 인덱스로 방문 체크를 해준다.

이동할 곳의 디저트를 아직 먹지 방문하지 않았다면 방문 체크를 해주고 다음 칸으로 이동한다.

이동할 때마다 디저트의 개수를 세주기 위해서  cnt 값을 +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
#include <iostream>
#include <cstring>
using namespace std;
 
int n, ans;
int sx, sy;
int map[20][20];
int dx[] = {1,1,-1,-1};
int dy[] = { 1,-1,-1,1 };
bool check[101];
 
void solve(int x, int y, int dir, int cnt) {
    
 
    //시작점인 경우
    if (x == sx && y == sy) {
    
            int nx = x + dx[dir];
            int ny = y + dy[dir];
            if (check[map[nx][ny]] == false) {
                check[map[nx][ny]] = true;
                solve(nx, ny, dir,cnt+1);
                check[map[nx][ny]] = false;
            }    
        
    }
    else {
 
        
        //현재 방향 유지하는 경우
        int nx = x + dx[dir];
        int ny = y + dy[dir];
        if (nx >= 0 && ny >= 0 && nx < n && ny < n) {
            if (check[map[nx][ny]] == false) {
                check[map[nx][ny]] = true;
                solve(nx, ny, dir, cnt+1);
                check[map[nx][ny]] = false;
            }
            else if (nx == sx && ny == sy) {
                //방문 표시가 되어있지만 출발점인 경우
                if (ans < cnt) {
                    ans = cnt;
                }
            }
        }
 
 
 
        //방향을 꺾는 경우
        dir += 1;
        if(dir > 3return;
        nx = x + dx[dir];
        ny = y + dy[dir];
        if (nx >= 0 && ny >= 0 && nx < n && ny < n) {
            if (check[map[nx][ny]] == false) {
                check[map[nx][ny]] = true;
                solve(nx, ny, dir, cnt+1);
                check[map[nx][ny]] = false;
            }
            else if (nx == sx && ny == sy) {
                //방문 표시가 되어있지만 출발점인 경우
                if (ans < cnt) {
                    ans = cnt;
                }
            }
        }
    }
    
 
 
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int T;
    cin >> T;
    
    for (int tc = 1; tc <= T; tc++) {
        cin >> n;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                cin >> map[i][j];
            }
        }
 
        ans = -1;
        memset(check, falsesizeof(check));
 
        //시작점
        for (int i = 0; i < n - 2; i++) {
            for (int j = 1; j < n - 1; j++) {
                sx = i;
                sy = j;
                check[map[i][j]] = true;
                solve(sx,sy,0,1);
                check[map[i][j]] = false;
                
            }
        }
 
        cout << '#' << tc << ' ' << ans << '\n';
    }
 
    return 0;
}
Colored by Color Scripter
 

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRUN9KfZ8DFAUo

 

SW Expert Academy

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

www.swexpertacademy.com

java로 두 번이나 풀어봤던 문제였는데 16진수로 변환하는 부분이 조금 달라서 푸는데 꽤 어려웠다...

 

 

먼저 한칸씩 회전시켜서 만들 수 있는 모든 숫자를 만들어야 하므로 N/4번만큼 돌려준다.

N/4번만큼 돌리면 처음 상태로 돌아오기 때문이다.

 

 

숫자를 구할 때는 먼저 문자들을 숫자로 변환해준다.

문자 0~9는 '0'을 빼줘서 숫자 0~9로 만들어주고

문자 A~F는 'A'를 빼주고(0이 됨) +10을 해주면 16진수 처럼만들어 줄 수 있다.

(ex. 'A' - 'A' + 10 = 10

      'B' - 'A' + 10 = 11)

 

 

모든 문자를 숫자로 만들어 줬으면 이제 각 변에 저장될 숫자를 만들어 준다.

상자는 네 번 이므로 각 변에는 n/4만큼의 숫자가 들어간다.

n/4개의 숫자를 하나의 숫자(16진수)로  만들어주기 위해서 앞자리 수를 16만큼 계속 곱해준다.

한 변의 숫자가 만들어졌으면 벡터에 추가하고 다음 변의 숫자를 만들어준다.

 

 

만들 수 있는 모든 숫자를 벡터에 넣어줬다면

벡터를 정렬하고 중복을 제거해준다.

k 번째로 큰 수를 구해야 하는데 오름차순으로 정렬되므로 

벡터의 size - k를 해주면 바로 k번째 큰 수를 구할 수 있다.

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
 
int n, k;
string s;
vector<int> num;
 
void getnum() {
    int box[4= {0,};
    int tmp[28];
 
    //각 문자를 숫자로 변환
    for (int i = 0; i < n; i++) {
        if (s[i] >= '0' && s[i] <= '9') {
            tmp[i] = s[i] - '0';
        }
        else { //A~F 는 10~15
            tmp[i] = s[i] - 'A' + 10;
        }
    }
 
 
    //상자의 각 변에 숫자를 넣는다.
    int index = 0;
    //상자의 네 변에 넣어준다.
    for (int i = 0; i < 4; i++) {
        
        //각각의 변에는 n/4개 만큼 들어간다
        for (int j = 0; j < n / 4; j++) {
            //16진수이므로 자릿수가 증가 할때 16을 곱해준다
            box[i] = box[i] * 16 + tmp[index++];
        }
 
        //만들어진 숫자를 벡터에 추가
        num.push_back(box[i]);
    }
 
    
}
 
 
 
void rotate() {
    char tmp = s[n - 1];
    for (int i = n - 1; i > 0; i--) {
        s[i] = s[i - 1];
    }
    s[0= tmp;
}
 
 
 
void solve() {
    
    // n/4 번째에는 0번째와 같아지므로 n/4번 회전
    for (int i = 0; i < n / 4; i++) {
        //만들 수 있는 숫자들을 구한다.
        getnum();
 
        //회전
        rotate();
    }
    
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
 
    int T;
    cin >> T;
    for (int tc = 1; tc <= T; tc++) {
        cin >> n >> k;
        cin >> s;
 
 
        solve();
 
 
        //정렬, 중복 제거
        sort(num.begin(), num.end());
        num.erase(unique(num.begin(), num.end()),num.end());
 
 
        //k번째 큰 수를 출력
        int len = num.size();
        cout << '#'<< tc << ' ' << num[len - k] << '\n';
 
 
        //다음 테스트 케이스를 위해서 벡터 초기화
        num.clear();
    }
 
    return 0;
}
Colored by Color Scripter
 

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5V61LqAf8DFAWu

 

SW Expert Academy

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

www.swexpertacademy.com

 

이 문제에서 k의 범위는 현재 좌표가 (x, y)라고 했을 때, 

k = |nx-x| + |ny-y|

를 이용해서 k의 범위를 만족하는 (nx, ny)를 구할 수 있다.

 

위의 식을 이용하여 모든 칸에서부터 모든 k의 범위 안에서 집의 수를 구한다.

문제에서 나오는 식을 이용하여 이익을 계산한 후에 손해가 아니라면(이익이 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
#include <iostream>
#include <cmath>
using namespace std;
 
int n, m;
int maxcnt;
int map[20][20];
 
 
void solve(int x, int y) {
    int profit = 0;
 
    //k의 최댓값 n+2 까지 해본다.
    for (int k = 1; k < n+2; k++) {
 
 
        //k범위에 있는 집들을 모두 세준다.
        int homecnt = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                int nx = abs(x - i);
                int ny = abs(y - j);
 
                //k범위 안에 있고 집이 있으면 집의 수 증가
                if (nx + ny < k && map[i][j] == 1) {
                    homecnt++;
                }
            }
        }
 
 
        //이익을 계산
        profit = m*homecnt - (k*+ (k - 1)*(k - 1));
        
        //손해가 아니라면 집의 수를 이전 집의 최대 값과 비교
        if (profit >= 0) {
            if (maxcnt < homecnt) maxcnt = homecnt;
        }
 
    }
}
 
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int T;
    cin >> T;
 
    for (int tc = 1; tc <= T; tc++) {
        maxcnt = 0;
        cin >> n >> m;
 
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                cin >> map[i][j];
            }
        }
 
 
        //모든 칸에서 시작
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                solve(i, j);
            }
        }
 
        cout <<'#' << tc << ' ' <<  maxcnt << '\n';
    }
 
    return 0;
}
Colored by Color Scripter
 

https://www.swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV2b7Yf6ABcBBASw&categoryId=AV2b7Yf6ABcBBASw&categoryType=CODE

 

SW Expert Academy

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

www.swexpertacademy.com

N이 20보다 작으므로 완전 탐색을 사용하여 풀었다.

모든 점원의 키를 선택하는 경우와 선택하지 않는 경우를 모두 구해준다.

그중에서 합이 b이상이면 b와의 차이를 구해 최솟값을 비교한다.

 

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
#include <cstdio>
using namespace std;
 
int tall[20];
int n,b,min;
 
void solve(int index, int sum) {
 
    //점원의 키를 선택할지 안할지 모두 정했으면
    if(index >= n) {
        //높이가 b 이상이어야 하므로 b보다 작은경우 return
        if(sum < b) return;
 
 
        //차이가 가장 작은 값을 구한다.
        int tmp = sum-b;
 
        //-1(초기값)이거나 기존의 최솟값보다 작은 경우
        if(min == -1 || min > tmp) {
            min = tmp;
        }
        return;
    }
 
 
    //index번째 점원의 키를 더하지 않는 경우
    solve(index+1, sum);
 
    //index번째 점원의 키를 더하는 경우
    solve(index+1, sum+tall[index]);
}
 
 
int main(){
    int T;
    scanf("%d"&T);
    
    
    for(int tc=1; tc<=T; tc++) {
        min = -1;
        scanf("%d %d"&n, & b);
 
        for(int i=0; i<n; i++) {
            scanf("%d"&tall[i]);
        }
 
        solve(0,0);
        printf("#%d %d\n", tc,min);
 
    }
    return 0;
}
Colored by Color Scripter
 

'SWEA > D4' 카테고리의 다른 글

[SWEA] 9282. 초콜릿과 건포도  (0) 2020.03.04
[SWEA] 1226. [S/W 문제해결 기본] 7일차 - 미로1  (0) 2019.06.27
[SWEA] 7829. 보물왕 태혁  (0) 2019.06.27

+ Recent posts