ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준 20058] 마법사 상어와 파이어스톰
    C 프로그래밍/BOJ 2022. 10. 11. 11:28
    728x90

    22.11.04. 다시 작성한 코드가 더 깔끔해서 갱신..

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

     

    20058번: 마법사 상어와 파이어스톰

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

    www.acmicpc.net

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <queue>
    int N, Q;
    int A[64 + 2][64 + 2];
    int L[1000 + 2];
    
    int M;
    int tmp[64 + 2][64 + 2];
    
    struct _st
    {
    	int x, y;
    };
    std::queue<_st> Ice;
    int visited[64 + 2][64 + 2];
    int total;
    
    int dir_x[4] = { 0, 0, 1, -1 };
    int dir_y[4] = { 1, -1, 0, 0 };
    
    
    void debug()
    {
    	for (int i = 0; i < M; i++) {
    		for (int j = 0; j < M; j++) {
    			printf("%d", A[i][j]);
    		}
    		printf("\n");
    	}
    }
    
    
    
    void input()
    {
    	scanf("%d %d", &N, &Q);
    	M = pow(2, N);
    	for (int i = 0; i < M; i++) {
    		for (int j = 0; j < M; j++) {
    			scanf("%d", &A[i][j]);
    		}
    	}
    	for (int i = 0; i < Q; i++) {
    		scanf("%d", &L[i]);
    	}
    }
    
    void fire_storm(int len)
    {
    	memset(tmp, 0, sizeof(tmp));
    
    	// rotate
    	for (int x = 0; x < M; x += len) {			
    		for (int y = 0; y < M; y += len) {	// 이때 만들어지는 (x, y)가 시작점이 된다. 
    			for (int i = 0; i < len; i++) {
    				for (int j = 0; j < len; j++) {
    					tmp[x + i][y + j] = A[x + len - j - 1][y + i];
    				}
    			}
    		}
    	}
    	memset(A, 0, sizeof(A));
    
    	// search ice
    	for (int i = 0; i < M; i++) {
    		for (int j = 0; j < M; j++) {
    			if (tmp[i][j] == 0) continue;	// 얼음이 없는 칸은 탐색해줄 필요 없다 
    			int ice = 0;
    			for (int p = 0; p < 4; p++) {
    				int nx = i + dir_x[p];
    				int ny = j + dir_y[p];
    				if (nx < 0 || nx > M - 1 || ny < 0 || ny > M - 1) continue;
    				if (tmp[nx][ny] != 0) ice++;
    			}
    			if (ice < 3) A[i][j] -= 1;
    		}
    	}
    
    	// del ice
    	for (int i = 0; i < M; i++) {
    		for (int j = 0; j < M; j++) {
    			A[i][j] += tmp[i][j];
    		}
    	}
    }
    
    
    
    void simul()
    {
    	for (int i = 0; i < Q; i++) {
    		fire_storm(pow(2, L[i]));
    	}
    }
    
    
    int BFS(int x, int y)
    {
    	Ice = {};
    
    	Ice.push({ x, y });
    	visited[x][y] = 1;
    	int cnt = 1;
    	total += A[x][y];
    
    	while (!Ice.empty()) {
    		_st data = Ice.front();
    		Ice.pop();
    
    		for (int p = 0; p < 4; p++) {
    			int nx = data.x + dir_x[p];
    			int ny = data.y + dir_y[p];
    
    			if (nx < 0 || nx > M - 1 || ny < 0 || ny > M - 1) continue;
    			if (A[nx][ny] == 0) continue;
    			if (visited[nx][ny]) continue;
    			cnt++;
    			total += A[nx][ny];
    			Ice.push({ nx, ny });
    			visited[nx][ny] = 1;
    		}
    	}
    	return cnt;
    }
    
    
    
    int output()
    {
    	int ice_berg = 0;
    	for (int i = 0; i < M; i++) {
    		for (int j = 0; j < M; j++) {
    			if (visited[i][j]) continue;
    			if (A[i][j] == 0) continue;
    			int cnt = BFS(i, j);
    			if (cnt == 1) continue;	// 덩어리가 안생김 // 격자 공간 하나의 값 
    			if (ice_berg < cnt) ice_berg = cnt;
    		}
    	}
    	return ice_berg;
    }
    
    
    int main()
    {
    	input();
    	simul();
    	printf("%d\n%d\n", total, output());
    	return 0;
    }

    큐를 활용하여 rotate한 풀이는 아래와 같다. 

    더보기
    저 런타임에러 ? ㅋㅋ... 또 인덱스 실수 ^^ 개빡친다
    #include <cstdio>
    #include <cmath>
    #include <queue>
    #include <algorithm>
    int N, Q;
    int M;	// 맵 크기
    int A[64 + 2][64 + 2];	// 원본 맵 
    int S[64 + 2][64 + 2];	// 복사 진행할 맵
    int L[1000 + 2];
    int visited[64 + 2][64 + 2];
    
    struct _st
    {
    	int x, y;
    };
    
    
    int dir_x[4] = { 0, 0, 1, -1 };
    int dir_y[4] = { 1, -1, 0, 0 };
    
    
    void input()
    {
    	scanf("%d %d", &N, &Q);
    	M = pow(2, N);
    	for (int i = 0; i < M; i++) {
    		for (int j = 0; j < M; j++) {
    			scanf("%d", &A[i][j]);
    		}
    	}
    	for (int i = 0; i < Q; i++) {
    		scanf("%d", &L[i]);
    	}
    }
    
    
    void rotate_ice(int x, int y, int m)
    {
    	std::queue<int> B;
    	int col = y;
    	for (int i = x + m - 1; i >= x; i--) {
    		for (int j = y + m - 1; j >= y; j--) {
    			B.push(A[i][j]);
    		}
    		for (int k = x + m - 1; k >= x; k--) {
    			S[k][col] = B.front();
    			B.pop();
    		}
    		col++;
    	}
    }
    
    
    
    void move_ice(int level)
    {
    	std::fill(&S[0][0], &S[0][0] + sizeof(S) / sizeof(int), 0);
    	int m = pow(2, level);
    	for (int i = 0; i < M; i += m) {
    		for (int j = 0; j < M; j += m) {
    			rotate_ice(i, j, m);
    		}
    	}
    }
    
    
    
    void del_ice()
    {
    	std::fill(&A[0][0], &A[0][0] + sizeof(A) / sizeof(int), 0);
    	for (int i = 0; i < M; i++) {
    		for (int j = 0; j < M; j++) {
    			if (S[i][j] == 0) continue;
    			int cnt = 0;
    			for (int p = 0; p < 4; p++) {
    				int ni = i + dir_x[p];
    				int nj = j + dir_y[p];
    
    				if (ni < 0 || ni > M || nj < 0 || nj > M) continue;
    				if (S[ni][nj] == 0) continue;
    				if (S[ni][nj]) cnt++;
    			}
    			if (cnt < 3) A[i][j] = S[i][j] - 1;
    			else A[i][j] = S[i][j];
    		}
    	}
    }
    
    
    
    
    void simul()
    {
    	for (int i = 0; i < Q; i++) {
    		move_ice(L[i]);
    		del_ice();
    	}
    }
    
    
    int sum_ice()
    {
    	int total = 0;
    	for (int i = 0; i < M; i++) {
    		for (int j = 0; j < M; j++) {
    			if (A[i][j] == 0) continue;
    			total += A[i][j];
    		}
    	}
    	return total;
    }
    
    
    
    
    int BFS(int x, int y)
    {
    	std::fill(&visited[0][0], &visited[0][0] + sizeof(visited) / sizeof(int), 0);
    	std::queue<_st> Que;
    	Que.push({ x, y});
    	visited[x][y] = 1;
    	int cnt = 1;	// 자기자신
    
    	while (!Que.empty()) {
    		_st data = Que.front();
    		Que.pop();
    
    		for (int p = 0; p < 4; p++) {
    			int nx = data.x + dir_x[p];
    			int ny = data.y + dir_y[p];
    
    			if (nx < 0 || nx > M || ny < 0 || ny > M) continue;
    			if (A[nx][ny] == 0) continue;
    			if (visited[nx][ny]) continue;
    			Que.push({ nx, ny});
    			visited[nx][ny] = 1;
    			cnt += 1;
    		}
    	}
    	return cnt;
    }
    
    
    int max_ice()
    {
    	int ans = 0;
    	for (int i = 0; i < M; i++) {
    		for (int j = 0; j < M; j++) {
    			if (A[i][j] == 0) continue;
    			int tmp = BFS(i, j);
    			ans = (tmp > ans) ? tmp : ans;
    		}
    	}
    	if (ans == 1) return 0;
    	return ans;
    }
    
    
    
    int main()
    {
    	input();
    	simul();
    	int total = sum_ice();
    	int iceberg = max_ice();
    	printf("%d\n%d\n", total, iceberg);
    	return 0;
    }

    아 ~~ 인덱스 실수 하지말라고 ~~~ 파이어스톰을 총 Q번 실행할 수 있는데 Q는 1000까지라잖아 ~~~~ 개바보야 ~~~ OOB 두개는 인덱스 100까지 줘서.... ㅋㅎ..

     

     

    // rotate_ice( ) 함수

    이거 그냥 90도 회전하는 코드로 구현하려고 했는데 그렇게 하면 source맵이랑 destination맵이랑 인덱스가 안맞아서 회전이 잘 안된다. (일단 나는 실패하긴 했는데 하신 분이 있을수도...) 그래서 나는 source맵에서 가장 마지막 행부터 첫번째 행 까지 탐색하는데, 열번호가 큰 것 부터 큐 B에 담고 이것을 destination 맵에서 열번호가 작은 것 부터 큰 것까지 옮겨주었다.

    // source 맵
    1  2  3  4 
    9  10 11 12 
    17 18 19 20
    25 26 27 28  > 가장 마지막 행의 마지막 열부터 (28, 27, 26, 25) 빼고 
    
    
    // destination 맵
    25
    26
    27
    28
    ^
    가장 첫행의 
    마지막 열부터 (28, 27, 26, 25)
    넣음

    // del_ice( ) 함수

    "얼음이 있는 칸 3개 또는 그 이상과 인접해있지 않은 칸" 이라고 했으므로, 특정 칸 (i, j)가 영역 외부와 인접해있는 경우 얼음이 없는 칸과 인접해 있다고 생각해야한다. 이 부분을 간과해서 디버깅하느라고 30분 이상 씀... ..... 역시 문제가 하라는 대로 해야한다... 킁스..

     

     

     

    728x90

    'C 프로그래밍 > BOJ' 카테고리의 다른 글

    [백준 21609] 상어 중학교  (0) 2022.10.13
    [백준 21680] 상어 초등학교  (0) 2022.10.12
    [백준 23288] 주사위 굴리기  (0) 2022.10.10
    [백준 17144] 미세먼지 안녕!  (0) 2022.10.10
    [백준 17779] 게리맨더링 2  (0) 2022.10.10

    댓글

Designed by Tistory.