[백준] 23290 마법사 상어와 복제

0

백준

목록 보기
142/271
post-thumbnail

[백준] 23290 마법사 상어와 복제

#include <algorithm>
#include <vector>
#include <queue>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;

int fishR[8] = { 0, -1, -1, -1, 0, 1, 1, 1 };
int fishC[8] = {-1, -1, 0, 1, 1, 1, 0, -1};

int sharkR[4] = {-1, 0, 1, 0};
int sharkC[4] = {0, -1, 0, 1};

bool inRange(int r, int c) {
	if (r < 0 || r >= 4) return false;
	if (c < 0 || c >= 4) return false;
	return true;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
		
	//4x4 격자 정보
	//격자 칸의 물고기 방향 저장 큐
	vector<vector<queue<int>>> fish (vector<vector<queue<int>>>(4, vector<queue<int>>(4, queue<int>())));
	//격자 칸의 물고기 냄새 발생 시점 저장 큐
	vector<vector<queue<int>>> fish_smell (vector<vector<queue<int>>>(4, vector<queue<int>>(4, queue<int>())));

	int m; //물고기 수
	int s; //연습 수

	//상어의 위치
	pair<int, int> shark;

	cin >> m >> s;

	for (int i = 0; i < m; ++i) {
		int x, y, d;
		cin >> x >> y >> d;

		fish[x-1][y-1].push(d-1);
	}

	cin >> shark.first >> shark.second;
	shark.first--;
	shark.second--;

	//연습 시작
	int time = 1;
	while (time <= s) {

		//1. 물고기 복제
		vector<vector<queue<int>>> fish_copy;
		for (int i = 0; i < 4; ++i) {
			vector<queue<int>> fish_row_copy;
			for (int j = 0; j < 4; ++j) {
				fish_row_copy.push_back(fish[i][j]);
			}
			fish_copy.push_back(fish_row_copy);
		}

		//2. 물고기 이동
		vector<vector<queue<int>>> fish_after(vector<vector<queue<int>>>(4, vector<queue<int>>(4, queue<int>())));

		for (int i = 0; i < 4; ++i) {
			for (int j = 0; j < 4; ++j) {
				while (!fish[i][j].empty()) {
					int fish_dir = fish[i][j].front();
					fish[i][j].pop();

					//모든 방향으로 이동 시도
					bool moved = false;
					for (int k = 0; k < 8; ++k) {
						int moveR = i + fishR[fish_dir];
						int moveC = j + fishC[fish_dir];

						//격자 범위 밖 이동 불가
						//상어칸 이동 불가
						//물고기 냄새칸 이동 불가
						if (!inRange(moveR, moveC) || (moveR == shark.first && moveC == shark.second) || !fish_smell[moveR][moveC].empty()) {
							//물고기 방향 반시계 방향으로 45도 회전 후 재시도
							if (fish_dir == 0) fish_dir = 7;
							else fish_dir--;
							continue;
						}
						
						//이동
						moved = true;
						fish_after[moveR][moveC].push(fish_dir);
						break;
					}
					//이동하지 못한 경우 물고기 제자리
					if (moved == false) fish_after[i][j].push(fish_dir);
				}
			}
		}

		//fish = fish_after
		for (int i = 0; i < 4; ++i) {
			for (int j = 0; j < 4; ++j) {
				while (!fish_after[i][j].empty()) {
					fish[i][j].push(fish_after[i][j].front());
					fish_after[i][j].pop();
				}
			}
		}

		//3. 상어 연속 3칸 이동

		//제외되는 물고기 수의 최대값
		int maxCntFish = -1;
		//제외되는 물고기 수가 최대로 될 때 사전순으로 제일 앞서는 상어의 이동 방향
		vector<int> sharkDir;

		//상어의 이동 방향 구하기
		for (int d1 = 0; d1 < 4; ++d1) {
			int firstR = shark.first + sharkR[d1];
			int firstC = shark.second + sharkC[d1];

			if (!inRange(firstR, firstC)) continue;

			int firstCntFish = fish[firstR][firstC].size();

			for (int d2 = 0; d2 < 4; ++d2) {
				int secondR = firstR + sharkR[d2];
				int secondC = firstC+ sharkC[d2];

				if (!inRange(secondR, secondC)) continue;
				
				int secondCntFish;
				//상어가 이동하며 이미 방문한 격자인 경우 격자의 물고기 이미 제외됨
				if (secondR == firstR && secondC == firstC) secondCntFish = 0;
				else secondCntFish = fish[secondR][secondC].size();

				for (int d3 = 0; d3 < 4; ++d3) {
					int thirdR = secondR + sharkR[d3];
					int thirdC = secondC + sharkC[d3];

					if (!inRange(thirdR, thirdC)) continue;

					int thirdCntFish;
					//상어가 이동하며 이미 방문한 격자인 경우 격자의 물고기 이미 제외됨
					if ((thirdR == firstR && thirdC == firstC)|| (thirdR == secondR && thirdC == secondC))
						thirdCntFish = 0;
					else thirdCntFish = fish[thirdR][thirdC].size();

					if (maxCntFish < firstCntFish + secondCntFish + thirdCntFish) {
						sharkDir.clear();
						sharkDir.push_back(d1); 
						sharkDir.push_back(d2);
						sharkDir.push_back(d3);
						maxCntFish = firstCntFish + secondCntFish + thirdCntFish;
					}
				}
			}
		}

		//상어 이동 & 물고기 제외 & 물고기 냄새 추가
		for (int i = 0; i < 3; ++i) {
			shark.first = shark.first + sharkR[sharkDir[i]];
			shark.second = shark.second + sharkC[sharkDir[i]];

			while (!fish[shark.first][shark.second].empty()) {
				fish[shark.first][shark.second].pop();
				fish_smell[shark.first][shark.second].push(time);
			}
		}

		//4. 2번 전 연습에서 생긴 물고기 냄새 제거
		for (int i = 0; i < 4; ++i) {
			for (int j = 0; j < 4; ++j) {
				while (!fish_smell[i][j].empty()) {
					if (fish_smell[i][j].front() <= (time - 2)) fish_smell[i][j].pop();
					else break;
				}
			}
		}

		//5. 물고기 복제 완료
		for (int i = 0; i < 4; ++i) {
			for (int j = 0; j < 4; ++j) {
				while (!fish_copy[i][j].empty()) {
					fish[i][j].push(fish_copy[i][j].front());
					fish_copy[i][j].pop();
				}
			}
		}

		time++;
	}
	
	//격자에 있는 물고기 수 구하기
	int ans = 0;
	for (int i = 0; i < 4; ++i) {
		for (int j = 0; j < 4; ++j) {
			ans += fish[i][j].size();
		}
	}
	cout << ans;

	return 0;
}

profile
Be able to be vulnerable, in search of truth

0개의 댓글