728x90
반응형
https://www.acmicpc.net/problem/21611
최종 코드
//
// main.cpp
// BJ21611
//
// Created by 최화연 on 2022/04/27.
//
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
int N, M;
int board[50][50] = {0, };
vector<pair<int, int>> cmd;
int dr[5] = {0, -1, 1, 0, 0};
int dc[5] = {0, 0, 0, -1, 1};
int dy[4] = {0, 1, 0, -1};
int dx[4] = {-1, 0, 1, 0};
int shark_r, shark_c;
int broken_beads[4] = {0, };
void break_beads(int d, int s) {
for (int ss=1; ss<=s; ss++) {
int r = shark_r + ss*dr[d];
int c = shark_c + ss*dc[d];
if (board[r][c] == 0) continue;
board[r][c] = 0;
}
}
void move_beads() {
int r = shark_r;
int c = shark_c;
int d = 0;
deque<int> dq;
for (int n=1; n<=N; n++) {
int nn = n;
if (n == N) nn = N-1;
for (int i=0; i<2; i++) {
for (int j=0; j<nn; j++) {
r += dy[d];
c += dx[d];
if (board[r][c] > 0) {
dq.push_back(board[r][c]);
board[r][c] = 0;
}
}
if (n == N) break;
d = (d+1)%4;
}
}
r = shark_r;
c = shark_c;
d = 0;
for (int n=1; n<=N; n++) {
int nn = n;
if (n == N) nn = N-1;
for (int i=0; i<2; i++) {
for (int j=0; j<nn; j++) {
r += dy[d];
c += dx[d];
if (dq.empty()) return;
board[r][c] = dq.front();
dq.pop_front();
}
if (n == N) return;
d = (d+1)%4;
}
}
}
bool explode_beads() {
int r = shark_r;
int c = shark_c;
int d = 0;
bool check = false;
deque<pair<int, int>> dq;
for (int n=1; n<=N; n++) {
int nn = n;
if (n == N) nn = N-1;
for (int i=0; i<2; i++) {
for (int j=0; j<nn; j++) {
r += dy[d];
c += dx[d];
if (dq.empty() || board[dq.front().first][dq.front().second] == board[r][c]) {
dq.push_back({r, c});
}
else {
if (dq.size() >= 4) {
check = true;
broken_beads[board[dq.front().first][dq.front().second]] += dq.size();
while (!dq.empty()) {
int rr = dq.front().first;
int cc = dq.front().second;
dq.pop_front();
board[rr][cc] = 0;
}
}
dq.clear();
dq.push_back({r, c});
}
}
if (n == N) break;
d = (d+1)%4;
}
}
return check;
}
void change_beads() {
int r = shark_r;
int c = shark_c;
int d = 0;
deque<pair<int, int>> dq;
deque<int> new_beads;
for (int n=1; n<=N; n++) {
int nn = n;
if (n == N) nn = N-1;
for (int i=0; i<2; i++) {
for (int j=0; j<nn; j++) {
r += dy[d];
c += dx[d];
if (dq.empty() || board[dq.front().first][dq.front().second] == board[r][c]) {
dq.push_back({r, c});
}
else {
new_beads.push_back(dq.size());
new_beads.push_back(board[dq.front().first][dq.front().second]);
dq.clear();
dq.push_back({r, c});
}
}
if (n == N) break;
d = (d+1)%4;
}
}
r = shark_r;
c = shark_c;
d = 0;
for (int n=1; n<=N; n++) {
int nn = n;
if (n == N) nn = N-1;
for (int i=0; i<2; i++) {
for (int j=0; j<nn; j++) {
r += dy[d];
c += dx[d];
if (!new_beads.empty()) {
board[r][c] = new_beads.front();
new_beads.pop_front();
}
else {
board[r][c] = 0;
}
}
if (n == N) break;
d = (d+1)%4;
}
}
}
void blizard() {
for(int i=0; i<M; i++) {
//1. 구슬 파괴하기
break_beads(cmd[i].first, cmd[i].second);
//2. 구슬 이동하기
move_beads();
//3. 구슬 폭발하기
bool check = explode_beads();
while (check) {
move_beads();
check = explode_beads();
}
//4. 구슬 변화하기
change_beads();
}
}
int main(int argc, const char * argv[]) {
cin >> N >> M;
for (int r=1; r<=N; r++) {
for (int c=1; c<=N; c++) {
cin >> board[r][c];
}
}
for (int m=0; m<M; m++) {
int d, s;
cin >> d >> s;
cmd.push_back({d, s});
}
shark_r = (N+1)/2;
shark_c = (N+1)/2;
blizard();
cout << broken_beads[1] + 2*broken_beads[2] + 3*broken_beads[3] << endl;
return 0;
}
풀이 과정
풀이 시간 1시간 6분
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
int N, M;
int board[50][50] = {0, };
vector<pair<int, int>> cmd;
int dr[5] = {0, -1, 1, 0, 0};
int dc[5] = {0, 0, 0, -1, 1};
int dy[4] = {0, 1, 0, -1};
int dx[4] = {-1, 0, 1, 0};
int shark_r, shark_c;
int broken_beads[4] = {0, };
void break_beads(int d, int s) {
for (int ss=1; ss<=s; ss++) {
int r = shark_r + ss*dr[d];
int c = shark_c + ss*dc[d];
if (board[r][c] == 0) continue;
board[r][c] = 0;
}
}
void move_beads() {
int r = shark_r;
int c = shark_c;
int d = 0;
deque<int> dq;
for (int n=1; n<=N; n++) {
int nn = n;
if (n == N) nn = N-1;
for (int i=0; i<2; i++) {
for (int j=0; j<nn; j++) {
r += dy[d];
c += dx[d];
if (board[r][c] > 0) {
dq.push_back(board[r][c]);
board[r][c] = 0;
}
}
if (n == N) break;
d = (d+1)%4;
}
}
r = shark_r;
c = shark_c;
d = 0;
for (int n=1; n<=N; n++) {
int nn = n;
if (n == N) nn = N-1;
for (int i=0; i<2; i++) {
for (int j=0; j<nn; j++) {
r += dy[d];
c += dx[d];
if (dq.empty()) return;
board[r][c] = dq.front();
dq.pop_front();
}
if (n == N) return;
d = (d+1)%4;
}
}
}
bool explode_beads() {
int r = shark_r;
int c = shark_c;
int d = 0;
bool check = false;
deque<pair<int, int>> dq;
for (int n=1; n<=N; n++) {
int nn = n;
if (n == N) nn = N-1;
for (int i=0; i<2; i++) {
for (int j=0; j<nn; j++) {
r += dy[d];
c += dx[d];
if (dq.empty() || board[dq.front().first][dq.front().second] == board[r][c]) {
dq.push_back({r, c});
}
else {
if (dq.size() >= 4) {
check = true;
broken_beads[board[dq.front().first][dq.front().second]] += dq.size();
while (!dq.empty()) {
int rr = dq.front().first;
int cc = dq.front().second;
dq.pop_front();
board[rr][cc] = 0;
}
}
dq.clear();
dq.push_back({r, c});
}
}
if (n == N) break;
d = (d+1)%4;
}
}
return check;
}
void change_beads() {
int r = shark_r;
int c = shark_c;
int d = 0;
deque<pair<int, int>> dq;
deque<int> new_beads;
for (int n=1; n<=N; n++) {
int nn = n;
if (n == N) nn = N-1;
for (int i=0; i<2; i++) {
for (int j=0; j<nn; j++) {
r += dy[d];
c += dx[d];
if (dq.empty() || board[dq.front().first][dq.front().second] == board[r][c]) {
dq.push_back({r, c});
}
else {
new_beads.push_back(dq.size());
new_beads.push_back(board[dq.front().first][dq.front().second]);
dq.clear();
dq.push_back({r, c});
}
}
if (n == N) break;
d = (d+1)%4;
}
}
r = shark_r;
c = shark_c;
d = 0;
for (int n=1; n<=N; n++) {
int nn = n;
if (n == N) nn = N-1;
for (int i=0; i<2; i++) {
for (int j=0; j<nn; j++) {
r += dy[d];
c += dx[d];
if (!new_beads.empty()) {
board[r][c] = new_beads.front();
new_beads.pop_front();
}
else {
board[r][c] = 0;
}
}
if (n == N) break;
d = (d+1)%4;
}
}
}
void blizard() {
for(int i=0; i<M; i++) {
//1. 구슬 파괴하기
break_beads(cmd[i].first, cmd[i].second);
//2. 구슬 이동하기
move_beads();
//3. 구슬 폭발하기
bool check = explode_beads();
while (check) {
move_beads();
check = explode_beads();
}
//4. 구슬 변화하기
change_beads();
}
}
int main(int argc, const char * argv[]) {
cin >> N >> M;
for (int r=1; r<=N; r++) {
for (int c=1; c<=N; c++) {
cin >> board[r][c];
}
}
for (int m=0; m<M; m++) {
int d, s;
cin >> d >> s;
cmd.push_back({d, s});
}
shark_r = (N+1)/2;
shark_c = (N+1)/2;
blizard();
cout << broken_beads[1] + 2*broken_beads[2] + 3*broken_beads[3] << endl;
return 0;
}
이전 풀이
풀이 시간 2시간 27분
문제에서 나와 있는 대로 순서대로 구현해 나가면 된다. 각 단계별로 모듈화해서 문제를 풀었는데, 디버그 하는 과정이 꽤나 오래걸렸다.
- 블리자드 마법 시전
- 구슬 이동
- 구슬 폭발이 일어나지 않을 때까지 반복
- 구슬 폭발
- 구슬 이동
- 구슬 변화
칸의 번호 순서대로 격자를 탐색하는 것을 구현하는 것이 핵심이라고 볼 수 있다.
이를 바탕으로 구슬을 이동시키고, 폭발을 일으키고, 구슬을 변화시킬 수 있기 때문이다.
칸을 탐색하는 과정을 살펴보면 규칙이 있다.
N = 7인 경우이다.
잘 보면 처음 상어의 위치에서부터 시작하여 방향이 바뀌는 기준이 발생하는 칸에 도달하기까지 이동해야하는 칸 수에 규칙이 있다.
이동해야하는 칸 수 = 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6
즉, 1~N-1까지 2번씩 반복하고, 마지막 가장 윗 행은 예외적으로 N-1칸 이동하면 된다.
방향은 좌, 하, 우, 상 순서대로 바뀐다.
이러한 규칙을 반영해서 칸의 번호 순서대로 탐색하는 코드는 다음과 같이 짤 수 있다.
//격자 탐색 방향
//0->좌, 1->하, 2->우, 3->상
int mc[4] = {-1, 0, 1, 0};
int mr[4] = {0, 1, 0, -1};
int r = shark_r;
int c = shark_c;
int ss = 0;
int d = 0;
bool check = true;
for(int s=1; s<=N; s++){
for(int i=1; i<=2; i++){
ss = s;
if(ss == N) ss--;
for(int j=1; j<=ss; j++){
//현재 칸 (r, c)
r += mr[d];
c += mc[d];
}
if(s == N){
check = false;
break;
}
d = (d+1)%4;
}
if(!check) break;
}
이를 활용해서 구슬 이동과 구슬 폭발, 구슬 변화 함수를 각각 짜보면 다음과 같다.
(1) 구슬 폭발
//폭발할 구슬의 그룹들을 담는 벡터
vector<vector<pair<int, int>>> beads_group;
//한 그룹의 구슬들을 담는 벡터
vector<pair<int, int>> beads;
//격자 탐색 방향
//0->좌, 1->하, 2->우, 3->상
int mc[4] = {-1, 0, 1, 0};
int mr[4] = {0, 1, 0, -1};
//bomb_beads_cnt[i] = 폭발한 구슬 i의 개수
int bomb_beads_cnt[4] = {0,};
//O(N^2)
int bead_bomb(){
beads_group.clear();
beads.clear();
int r = shark_r;
int c = shark_c;
int ss = 0;
int d = 0;
bool check = true;
for(int s=1; s<=N; s++){
for(int i=1; i<=2; i++){
ss = s;
if(ss == N) ss--;
for(int j=1; j<=ss; j++){
r += mr[d];
c += mc[d];
//구슬 그룹이 없는 경우, 새 구슬 그룹을 만든다
if(beads.empty()) beads.push_back({r, c});
//그룹의 구슬 종류와 현재 칸의 구슬 종류가 같은 경우, 그룹에 추가한다
else if(board[beads.back().first][beads.back().second] == board[r][c]){
beads.push_back({r, c});
}
//그룹의 구슬 종류와 현재 칸의 구슬 종류가 다른 경우,
else{
//이전 그룹의 구슬 개수가 4개 이상인 경우, 폭발이 일어나야하므로 beads_group에 해당 그룹을 추가한다
if(beads.size() >= 4) beads_group.push_back(beads);
//새 구슬 그룹을 만든다
beads.clear();
beads.push_back({r, c});
}
}
if(s == N){
check = false;
break;
}
d = (d+1)%4;
}
if(!check) break;
}
//폭발해서 사라진 구슬 수
int cnt = 0;
for(int i=0; i<beads_group.size(); i++){
//폭발한 구슬의 개수 카운팅
bomb_beads_cnt[board[beads_group[i].back().first][beads_group[i].back().second]] += beads_group[i].size();
cnt += beads_group[i].size();
//폭발한 구슬을 없앤다
for(int j=0; j<beads_group[i].size(); j++){
board[beads_group[i][j].first][beads_group[i][j].second] = 0;
}
}
return cnt;
}
(2) 구슬 이동
//격자 탐색 방향
//0->좌, 1->하, 2->우, 3->상
int mc[4] = {-1, 0, 1, 0};
int mr[4] = {0, 1, 0, -1};
//O(N^2)
void move_beads(){
//현재 칸 위치
int r = shark_r;
int c = shark_c;
//이전 칸 위치
int br = shark_r;
int bc = shark_c;
int ss = 0;
int d = 0;
for(int s=1; s<=N; s++){
for(int i=1; i<=2; i++){
ss = s;
if(ss == N) ss--;
for(int j=1; j<=ss; j++){
r += mr[d];
c += mc[d];
//이전 칸에 구슬이 없는 경우
if(board[br][bc] == 0){
//이전 칸에 현재 칸의 구슬을 담고, 현재 칸은 비운다
board[br][bc] = board[r][c];
board[r][c] = 0;
}
br = r;
bc = c;
}
if(s == N) return;
d = (d+1)%4;
}
}
}
(3) 구슬 변화
//구슬의 그룹들을 담는 벡터
vector<vector<pair<int, int>>> beads_group;
//한 그룹의 구슬들을 담는 벡터
vector<pair<int, int>> beads;
//새로운 구슬을 담는 벡터
//new_beads[i] = i+1번째 구슬의 종류
vector<int> new_beads;
//격자 탐색 방향
//0->좌, 1->하, 2->우, 3->상
int mc[4] = {-1, 0, 1, 0};
int mr[4] = {0, 1, 0, -1};
//O(N^2)
void change_beads(){
beads_group.clear();
beads.clear();
int r = shark_r;
int c = shark_c;
int ss = 0;
int d = 0;
bool check = true;
for(int s=1; s<=N; s++){
for(int i=1; i<=2; i++){
ss = s;
if(ss == N) ss--;
for(int j=1; j<=ss; j++){
r += mr[d];
c += mc[d];
//구슬 그룹이 없는 경우, 새 그룹을 만든다
if(beads.empty()) beads.push_back({r, c});
//그룹의 구슬 종류와 현재 구슬 종류가 같은 경우, 현재 구슬을 그룹에 추가한다
else if(board[beads.back().first][beads.back().second] == board[r][c]){
beads.push_back({r, c});
}
//그룹의 구슬 종류와 현재 구슬 종류가 다른 경우,
else{
//이전 구슬 그룹을 beads_group에 추가하고 새 그룹을 만든다
beads_group.push_back(beads);
beads.clear();
beads.push_back({r, c});
}
}
if(s == N){
check = false;
break;
}
d = (d+1)%4;
}
if(!check) break;
}
//구슬 변화
int A = 0;
int B = 0;
new_beads.clear();
//각각의 구슬 그룹에 대한 A, B를 만들고 new_beads에 순서대로 추가한다
for(int i=0; i<beads_group.size(); i++){
A = beads_group[i].size();
B = board[beads_group[i].back().first][beads_group[i].back().second];
new_beads.push_back(A);
new_beads.push_back(B);
}
//새로운 구슬을 격자에 적용
r = shark_r;
c = shark_c;
ss = 0;
d = 0;
//new_beads 벡터 인덱스
int k = 0;
check = true;
for(int s=1; s<=N; s++){
for(int i=1; i<=2; i++){
ss = s;
if(ss == N) ss--;
for(int j=1; j<=ss; j++){
r += mr[d];
c += mc[d];
//새로운 구슬들을 모두 격자에 반영했다면, 이후 칸에는 모두 0을 넣는다
if(k >= new_beads.size()) board[r][c] = 0;
//k번째 새로운 구슬을 격자에 넣는다
else board[r][c] = new_beads[k];
k++;
}
if(s == N){
check = false;
break;
}
d = (d+1)%4;
}
if(!check) break;
}
}
#include <iostream>
#include <vector>
using namespace std;
int N, M;
//블리자드 마법 방향
//1->상, 2->하, 3->좌, 4->우
int dr[5] = {0, -1, 1, 0, 0};
int dc[5] = {0, 0, 0, -1, 1};
//격자 탐색 방향
//0->좌, 1->하, 2->우, 3->상
int mc[4] = {-1, 0, 1, 0};
int mr[4] = {0, 1, 0, -1};
int board[50][50] = {0, };
//blizards[i] = {d, s}
vector<pair<int, int>> blizards;
//구슬의 그룹들을 담는 벡터
vector<vector<pair<int, int>>> beads_group;
//한 그룹의 구슬들을 담는 벡터
vector<pair<int, int>> beads;
vector<int> new_beads;
int shark_r = 0;
int shark_c = 0;
//bomb_beads_cnt[i] = 폭발한 구슬 i의 개수
int bomb_beads_cnt[4] = {0,};
void move_beads(){
//현재 칸 위치
int r = shark_r;
int c = shark_c;
//이전 칸 위치
int br = shark_r;
int bc = shark_c;
int ss = 0;
int d = 0;
for(int s=1; s<=N; s++){
for(int i=1; i<=2; i++){
ss = s;
if(ss == N) ss--;
for(int j=1; j<=ss; j++){
r += mr[d];
c += mc[d];
//이전 칸에 구슬이 없는 경우
if(board[br][bc] == 0){
//이전 칸에 현재 칸의 구슬을 담고, 현재 칸은 비운다
board[br][bc] = board[r][c];
board[r][c] = 0;
}
br = r;
bc = c;
}
if(s == N) return;
d = (d+1)%4;
}
}
}
int bead_bomb(){
beads_group.clear();
beads.clear();
int r = shark_r;
int c = shark_c;
int ss = 0;
int d = 0;
bool check = true;
for(int s=1; s<=N; s++){
for(int i=1; i<=2; i++){
ss = s;
if(ss == N) ss--;
for(int j=1; j<=ss; j++){
r += mr[d];
c += mc[d];
//구슬 그룹이 없는 경우, 새 구슬 그룹을 만든다
if(beads.empty()) beads.push_back({r, c});
//그룹의 구슬 종류와 현재 칸의 구슬 종류가 같은 경우, 그룹에 추가한다
else if(board[beads.back().first][beads.back().second] == board[r][c]){
beads.push_back({r, c});
}
//그룹의 구슬 종류와 현재 칸의 구슬 종류가 다른 경우,
else{
//이전 그룹의 구슬 개수가 4개 이상인 경우, 폭발이 일어나야하므로 beads_group에 해당 그룹을 추가한다
if(beads.size() >= 4) beads_group.push_back(beads);
//새 구슬 그룹을 만든다
beads.clear();
beads.push_back({r, c});
}
}
if(s == N){
check = false;
break;
}
d = (d+1)%4;
}
if(!check) break;
}
//폭발해서 사라진 구슬 수
int cnt = 0;
for(int i=0; i<beads_group.size(); i++){
//폭발한 구슬의 개수 카운팅
bomb_beads_cnt[board[beads_group[i].back().first][beads_group[i].back().second]] += beads_group[i].size();
cnt += beads_group[i].size();
//폭발한 구슬을 없앤다
for(int j=0; j<beads_group[i].size(); j++){
board[beads_group[i][j].first][beads_group[i][j].second] = 0;
}
}
return cnt;
}
void change_beads(){
beads_group.clear();
beads.clear();
int r = shark_r;
int c = shark_c;
int ss = 0;
int d = 0;
bool check = true;
for(int s=1; s<=N; s++){
for(int i=1; i<=2; i++){
ss = s;
if(ss == N) ss--;
for(int j=1; j<=ss; j++){
r += mr[d];
c += mc[d];
//구슬 그룹이 없는 경우, 새 그룹을 만든다
if(beads.empty()) beads.push_back({r, c});
//그룹의 구슬 종류와 현재 구슬 종류가 같은 경우, 현재 구슬을 그룹에 추가한다
else if(board[beads.back().first][beads.back().second] == board[r][c]){
beads.push_back({r, c});
}
//그룹의 구슬 종류와 현재 구슬 종류가 다른 경우,
else{
//이전 구슬 그룹을 beads_group에 추가하고 새 그룹을 만든다
beads_group.push_back(beads);
beads.clear();
beads.push_back({r, c});
}
}
if(s == N){
check = false;
break;
}
d = (d+1)%4;
}
if(!check) break;
}
//구슬 변화
int A = 0;
int B = 0;
new_beads.clear();
//각각의 구슬 그룹에 대한 A, B를 만들고 new_beads에 순서대로 추가한다
for(int i=0; i<beads_group.size(); i++){
A = beads_group[i].size();
B = board[beads_group[i].back().first][beads_group[i].back().second];
new_beads.push_back(A);
new_beads.push_back(B);
}
//새로운 구슬을 격자에 적용
r = shark_r;
c = shark_c;
ss = 0;
d = 0;
//new_beads 벡터 인덱스
int k = 0;
check = true;
for(int s=1; s<=N; s++){
for(int i=1; i<=2; i++){
ss = s;
if(ss == N) ss--;
for(int j=1; j<=ss; j++){
r += mr[d];
c += mc[d];
//새로운 구슬들을 모두 격자에 반영했다면, 이후 칸에는 모두 0을 넣는다
if(k >= new_beads.size()) board[r][c] = 0;
//k번째 새로운 구슬을 격자에 넣는다
else board[r][c] = new_beads[k];
k++;
}
if(s == N){
check = false;
break;
}
d = (d+1)%4;
}
if(!check) break;
}
}
void play_blizards(){
for(int i=0; i<M; i++){
//1. 블리자드 시전 -> O(1)
for(int s=blizards[i].second; s>=1; s--){
int br = shark_r + dr[blizards[i].first]*s;
int bc = shark_c + dc[blizards[i].first]*s;
board[br][bc] = 0;
}
//2. 구슬 이동 -> O(N^2)
for(int j=0; j<=blizards[i].second; j++) move_beads();
//3. 구슬 폭발 -> O(N^2)
int cnt = bead_bomb();
//4. 구슬 이동 -> O(N^4)
while(cnt > 0){
for(int j=1; j<=cnt; j++) move_beads();
cnt = bead_bomb();
}
//5. 구슬 변화 -> O(N^2)
change_beads();
}
}
int main(int argc, const char * argv[]) {
cin >> N >> M;
for(int r=1; r<=N; r++){
for(int c=1; c<=N; c++){
cin >> board[r][c];
}
}
for(int i=0; i<M; i++){
int d, s;
cin >> d >> s;
blizards.push_back({d, s});
}
shark_r = (N+1)/2;
shark_c = (N+1)/2;
board[shark_r][shark_c] = -1;
play_blizards();
cout << 1*bomb_beads_cnt[1] + 2*bomb_beads_cnt[2] + 3* bomb_beads_cnt[3] << endl;
return 0;
}
//시간복잡도 = O(M*N^4), 공간복잡도 = O(N^2)
728x90
반응형
'코테 노트 > 백준' 카테고리의 다른 글
백준 16236 아기 상어 C++ (0) | 2021.10.20 |
---|---|
백준 12100 2048(Easy) C++ (0) | 2021.10.17 |
백준 20056 마법사 상어와 파이어볼 C++ (0) | 2021.10.14 |
백준 21609 상어 중학교 C++ (0) | 2021.10.14 |
백준 20061 모노미노도미노 2 C++ (0) | 2021.10.14 |