본문 바로가기

백준/삼성기출

청소년 상어/ 백트래킹

728x90

www.acmicpc.net/problem/19236

 

19236번: 청소년 상어

첫째 줄부터 4개의 줄에 각 칸의 들어있는 물고기의 정보가 1번 행부터 순서대로 주어진다. 물고기의 정보는 두 정수 ai, bi로 이루어져 있고, ai는 물고기의 번호, bi는 방향을 의미한다. 방향 bi는

www.acmicpc.net

#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<deque>
#include<math.h>
#include<cmath>
#include<unordered_map>

using namespace std;

int dx[] = {0,-1,-1,0,1,1,1,0,-1};
int dy[] = {0,0,-1,-1,-1,0,1,1,1};

int n = 4;
int maxnum = 0;

struct fish {
	
	int num;
	int way;
};


vector<vector<fish>>arr(4, vector<fish>(4));

fish nothing = { 0,0 };

bool canGo(int x, int y)
{
	return x >= 0 && y >= 0 && x < n && y < n && arr[x][y].num != 17;
}

bool sharkCanGo(int x, int y) {

	return x >= 0 && y >= 0 && x < n && y < n ;

}

void print() {
	
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++)
		{
			
			cout <<"("<< arr[i][j].num<<","<<arr[i][j].way<<")"<<" ";
			
		}

		cout << endl;
	}
	cout << endl;

}


void fishMove(fish& f, int x, int y, map<int, pair<int, int>>&fishloc) {

	int way = f.way;
	int nx = x + dx[way];
	int ny = y + dy[way];

	int count = 1;

	while (!canGo(nx, ny)) {
		
		if (count == 8) { return; }
		way = (way + 1) % 8;
		if (way == 0) { way = 8; }
		nx = x + dx[way];
		ny = y + dy[way];
		count++;
	
	}


	if (arr[nx][ny].num != 0) { //만약에 빈칸이 아닌 물고기가 있는 경우
		pair<int, int>temp;
		temp = fishloc[arr[nx][ny].num];
		fishloc[arr[nx][ny].num] = fishloc[arr[x][y].num]; // 두 물고기의 정보를 저장
		fishloc[arr[x][y].num] = temp;
	}
	else {  //빈칸인 경우
		fishloc[arr[x][y].num] = make_pair(nx, ny);  // 옮길 물고기의 정보만 저장
	}
	arr[x][y].way = way;
	swap(arr[x][y], arr[nx][ny]);

}

void sharkMove(map<int,pair<int, int >> &fishloc, int nx, int ny) {

	int x = fishloc[17].first;
	int y = fishloc[17].second;

	swap(arr[x][y], arr[nx][ny]); // 상어와 물고기 바꾸기

	arr[nx][ny].way = arr[x][y].way;  // 원래있던 물고기의 방향으로 변경
	fishloc[17] = make_pair(nx, ny);  // 
	
	fishloc.erase(arr[x][y].num);  //기존의 물고기 없애기
	arr[x][y] = nothing;

}


void simulate(fish & shark, map<int, pair<int, int>>&fishloc) {
	
	map<int, pair<int, int>>::iterator it;

	for (it = fishloc.begin(); it != fishloc.end(); it++) {
		
		if (it->first != 17) {

			fishMove(arr[it->second.first][it->second.second], it->second.first, it->second.second, fishloc);

		}
	}


}


void dfs(fish & shark, map<int, pair<int, int>>&fishloc,int fishEat) {
	
	simulate(shark, fishloc); //시뮬레이션 먼저 한다.
	
	int way = shark.way;
	int nx = fishloc[17].first+dx[way];
	int ny = fishloc[17].second+dy[way];

	fish originShark = shark;
	map<int, pair<int, int>> originfishloc = fishloc;
	vector<vector<fish>>originarr = arr;

	while (1) {
		if (sharkCanGo(nx, ny)) { //상어가 갈 수 있는 영역 인지 판단
			if (arr[nx][ny].num != 0) { 

				int fnum = arr[nx][ny].num;   //이동하는 곳의 물고기 번호

				shark.way = arr[nx][ny].way;  //물고기의 방향과 동일하게 변경


				sharkMove(fishloc, nx, ny); // 상어 움직이기

				dfs(shark, fishloc, fishEat + fnum);

				//상태 복원
				arr = originarr;
				shark = originShark;
				fishloc = originfishloc;

			}

			nx = nx + dx[way];
			ny = ny + dy[way];
		}
		else {
			break; //더이상 갈 수 없으면 while문 빠져나옴.
		}

	}

	if (!sharkCanGo(nx, ny)) {  //기저조건 ** 기저조건을 함수의 마지막 부분에 배치해야하는 것 주의 ** 

		if (maxnum < fishEat) { 
			maxnum = fishEat;
		}

		return;
	}


}






int main() {

	map<int,pair<int, int>>fishloc;
	
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			
			int a,b;
			cin >> a >> b;
			fish f = { a,b };
			fishloc[a] = make_pair(i, j);
			arr[i][j] = f;
		
		}
	}

	int fnum = arr[0][0].num;

	fish shark = { 17,arr[0][0].way };
	fishloc.erase(arr[0][0].num);
	fishloc[17] = make_pair(0, 0);
	arr[0][0] = shark;
	
	dfs(shark, fishloc, fnum); 
	cout << maxnum<<endl;

}

- 보통 재귀함수에서 기저조건을 앞에 다 두는데 그렇게 하다가 계속 틀려서 기저조건을 함수의 마지막에 두었더니 잘 되었다. 

- 시뮬레이션 -> 조건 검사(while 문, 재귀) -> 조건 불만족 시 while 문 빠져나오고 리턴

'백준 > 삼성기출' 카테고리의 다른 글

드래곤 커브  (0) 2021.04.18
어른상어/ 시뮬레이션  (0) 2021.04.12
주사위 윷놀이, 비트연산자  (0) 2021.04.12
게리맨더링2/ 구현  (0) 2021.04.08
사다리조작 / 브루트포스  (0) 2021.04.05