반응형
f
재미있었는데 힘들었다..
키포인트는 이러했다.
1. 구름의 위치가 이동할 때, 배열이 연결되어 있다는 점을 인지
-> 적절한 식을 구성해주어야 한다.
2. 물복사를 시전할 때, 찾음과 동시에 바로 값을 갱신해버리면, 이후에 다른 위치의 물복사를 할 때 값 계산에 오류가 생길 수 있음
-> 물복사 할 위치를 미리 계산만 해 놓았다가, 나중에 한꺼번에 갱신
나는 구름의 위치를 저장하는데 set 알고리즘을 사용했고,
한 phase 마다
처음 구름, 이동된 구름, 새로 생성된 구름
이렇게 세 개의 set을 결국 사용하게 되었다.
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int N, M;
int mx[8] = {0, -1, -1, -1, 0, 1, 1, 1};
int my[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
int tx[4] = {-1, -1, 1, 1};
int ty[4] = {-1, 1, -1, 1};
set<pair<int, int>> cloud;
void perform(int dir, int len, vector<vector<int>>& v) {
set<pair<int, int>> moved_cloud; // cloud가 이동하여 moved_cloud 위치를 게산할 것임
// 1 ~ 2 번
for(auto c : cloud) { // auto c는 '복제' 다 !!
c.first = c.first + mx[dir - 1] * len; // 방향도 0 base 이니까 -1 해줌
c.second = c.second + my[dir - 1] * len; // 방향도 0 base 이니까 -1 해줌
c.first = c.first % N;
c.first = c.first >= 0 ? c.first : N - (abs(c.first) % N); // 음수면 처리
c.second = c.second % N;
c.second = c.second >= 0 ? c.second : N - (abs(c.second) % N); // 음수면 처리
v[c.first][c.second]++; // 구름이 이동한 뒤 해당 위치에 물 증가
moved_cloud.insert({c.first, c.second});
}
cloud = moved_cloud; // cloud 위치 갱신
// 출력해봄
// for(int i = 0; i < N; i++) {
// for(int j = 0; j < N; j++) {
// cout << v[i][j] << " ";
// }
// cout << "\n";
// }
//
// cout << "\n";
//4 번
// 물 복사에 대한 정보를 저장할 벡터
vector<vector<int>> copy_water(N, vector<int>(N, 0));
for(auto c : cloud) {
for(int i = 0; i < 4; i++) {
int xx = c.first + tx[i];
int yy = c.second + ty[i];
if(xx < 0 || xx >= N || yy < 0 || yy >= N)
continue;
if(v[xx][yy] > 0) // 대각선에 물이 채워져 있다 = 물복사
copy_water[c.first][c.second]++; // 물복사 할 수치 미리 저장. 여기서 바로 갱신해버리면, 이후 책정에 오류가 생길 수 있기에.
}
}
// 저장해놨던 물 복사 위치들에 대해 값 갱신
for(int i = 0 ; i < N; i++) {
for(int j = 0; j < N; j++) {
if(copy_water[i][j] > 0)
v[i][j] += copy_water[i][j];
}
}
// 출력해봄
// for(int i = 0; i < N; i++) {
// for(int j = 0; j < N; j++) {
// cout << v[i][j] << " ";
// }
// cout << "\n";
// }
//
// cout << "\n";
//
//
// 새로 생길 cloud의 위치들을 저장할 new_cloud
set<pair<int, int>> new_cloud;
for(int i = 0; i < N; i++) {
for(int j = 0; j < N; j++) {
// set의 find가 값을 찾을 수 없으면, end()와 같은 iterator를 리턴한다.
if(v[i][j] >= 2 && cloud.find({i, j}) == cloud.end()) {
new_cloud.insert({i, j});
v[i][j] -= 2;
}
}
}
// cloud 갱신
cloud = new_cloud;
// 출력해봄
// for(int i = 0; i < N; i++) {
// for(int j = 0; j < N; j++) {
// cout << v[i][j] << " ";
// }
// cout << "\n";
// }
//
// cout << "\n";
//
}
int main() {
int dir, len;
cin >> N >> M;
vector<vector<int>> v(N, vector<int>(N, 0));
for(int i = 0; i < N; i++) {
for(int j = 0; j < N; j++) {
cin >> v[i][j];
}
}
// 문제는 1 base이고, 나는 0 base 니까 -1씩 해줬음.
cloud.insert({N - 1, 0}); cloud.insert({N - 1, 1});
cloud.insert({N - 2, 0}); cloud.insert({N - 2, 1});
while(M--) {
cin >> dir >> len; // 방향과 길이 입력
perform(dir, len, v);
}
int AA = 0;
for(int i = 0; i < N; i++) {
for(int j = 0; j < N; j++) {
AA += v[i][j];
}
}
cout << AA << "\n";
}
그리고 문제를 풀면서 알게된 점은 두 가지 있다.
1.
-1 % 5 => -1
-2 % 5 => -2
-5 % 5 => 0
2. for(auto x : list) 구문에서, x는 '복사'된 상태다.
x를 갱신한다고 해서 list 내부가 정말 갱신되지 않는다.
3. set의 iterator로는 원소 값 변경이 불가능하다.
-> set의 특성이다. erase 후 insert 해야한다.
4. set 자료구조에서 find() 사용 시, 원소가 발견되지 않으면 end() 함수와 같은 iterator를 리턴하며
발견될 시에는 해당 위치의 iterator를 리턴한다.
5. 디버거는 꼭 필요하다........

풀만 했는데, 확실한건 매 과정을 출력하면서 디버깅도 할 수 있었기에 풀 수 있었다.
그게 안되면 절대 못 풀었을 듯.
started at 22:13
ended at 23:38
반응형
'[알고리즘 + 자료구조] > [백준]' 카테고리의 다른 글
[BaekJoon/백준] 20058번 마법사 상어와 파이어스톰 (0) | 2022.10.09 |
---|---|
[BaekJoon/백준] 20056번 마법사 상어와 파이어볼 (0) | 2022.10.08 |
[BaekJoon/백준] 20057번 마법사 상어와 토네이도 (0) | 2022.10.06 |
[BaekJoon/백준] 14890 경사로 (0) | 2022.08.05 |
[BaekJoon/백준] 5558번 Cheese (0) | 2022.08.04 |