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

 

17143번: 낚시왕

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다. 칸에는 상어가 최대 한 마리 들어있을 수 있다. 상어는 크기와 속도를 가지고 있다. 낚시왕은 처음에 1번 열의 한 칸 왼쪽에 있다. 다음은 1초 동안 일어나는 일이며, 아래 적힌 순서대로 일어난다. 낚시왕은 가장 오른쪽 열의 오른쪽 칸에 이동하

www.acmicpc.net

필요한 상어에 대한 정보를 담아서 구조체를 만든다.

 

이후에는 착실하게 시뮬레이션을 진행해주면 된다.

 

 

 

 

나 같은 경우에는 이전에 나무재테크 문제를 풀 때를 떠올려서, 한 칸에 상어가 여러 마리 들어가는 경우가 생기기 때문에 배열로 벡터를 잡았다.

 

먼저 상어의 이동과 관련된 구현이다.

 

문제에서 상어의 속력은 1000까지 가능하다고 했는데, 이 부분에서 나름 연산의 횟수를 줄여보겠다고 행과 열의 길이를 활용해서 모듈러 연산을 사용했다.

 

그런데 생각하지 못한 부분이 있었어서 프린트를 찍어가며 디버깅을 하는 데에 애를 먹었다.

 

그냥 속편하게 속도만큼 반복문을 돌리면서 (완벽한 통제를 위해서 for문을 사용하는 것이 낫겠다) 속도만큼 칸을 이동해주고, 이동한 칸이 범위를 벗어난다면 다시 바로잡아주는 식으로 하는 것이 조금 더 쉽고 직관적으로 구현할 수 있는 방법인 것 같다.

 

다른 부분은 상어가 먹히는 부분이다.

 

나는 일단 상어는 다 칸에 들어갈 수 있고, 그 이후에 가장 큰 상어를 찾아서 그 상어만 두고 나머지 상어는 다 제거하는 방식으로 구현을 했다.

 

 

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

 

16235번: 나무 재테크

부동산 투자로 억대의 돈을 번 상도는 최근 N×N 크기의 땅을 구매했다. 상도는 손쉬운 땅 관리를 위해 땅을 1×1 크기의 칸으로 나누어 놓았다. 각각의 칸은 (r, c)로 나타내며, r은 가장 위에서부터 떨어진 칸의 개수, c는 가장 왼쪽으로부터 떨어진 칸의 개수이다. r과 c는 1부터 시작한다. 상도는 전자통신공학과 출신답게 땅의 양분을 조사하는 로봇 S2D2를 만들었다. S2D2는 1×1 크기의 칸에 들어있는 양분을 조사해 상도에게 전송하고, 모든

www.acmicpc.net

 

특별한 알고리즘이랄 것이 없지만, 벡터를 활용하는 약간의 센스가 필요하다.

 

정수를 담는 벡터 자료형을 이차원 배열로 선언한다.

 

그래야 이차원 좌표상의 한 공간에 나무가 여러개 쌓이는 효과를 볼 수 있다.

 

그리고, 여름에 나무의 삭제가 발생할 때, 삭제되는 나무에 대한 처리를 할 때, vector.erase를 사용하고, 삭제되는 나무들에 대한 정보를 큐로 옮긴 이후에, 큐에서 pop하면서 처리를 해서 시간초과를 받았다.

 

이를 해결하기위해서, 봄에 땅으로부터 영양분을 흡수하는 것은 어짜피 나무가 나이로 정렬된 상태로 이루어지고, 특정 나이가 땅의 양분보다 많은 순간이 온다면, 그 나무보다 나이가 많은 나무들은 자연스럽게 확인할 가치가 없어지기 때문에, 봄에 영양분을 흡수했던 나무들을 임시 벡터에 넣어두고, 실패지점 이후에 원본 벡터를 clear한 이후에, 임시 벡터에 들어있는 데이터를 원래 벡터에 옮겨주면 여름에 대한 구현을 할 수 있다.

 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
ll grd[11][11];
int igr[11][11], n, m, k;
vector<ll> v[11][11];
int dr[8] = { -1, -1, 0, 1, 1, 1, 0, -1 };
int dc[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
int main(void) {
	//1-indexed
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> igr[i][j];
			grd[i][j] = 5;
		}
	}
	for (int i = 1; i <= m; i++) {
		int r, c, age;
		cin >> r >> c >> age;
		v[r][c].push_back(age);
	}
	for (int i = 1; i <= k; i++) {
		//봄
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				if (v[i][j].size() > 0) { //i행 j열에 나무가 존재하면
					vector<ll> tmp;
					sort(v[i][j].begin(), v[i][j].end()); //어린 나무부터
					//땅양분이 나이보다 많으면 나이 증가, 땅 양분 감소
					ll dead = 0;
					for (int t = 0; t < v[i][j].size(); t++) {
						if (v[i][j][t] <= grd[i][j]) {
							tmp.push_back(v[i][j][t] + 1);
							grd[i][j] -= v[i][j][t];
						}
						else {
							dead += v[i][j][t] / 2;
						}
					}
					//여름
					v[i][j].clear();
					v[i][j] = tmp;
					grd[i][j] += dead;
				}
			}
		}

		//가을
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				if (v[i][j].size() > 0) {
					for (int t = 0; t < v[i][j].size(); t++) {
						if (v[i][j][t] % 5 == 0) {
							for (int ii = 0; ii < 8; ii++) {
								int nr = i + dr[ii];
								int nc = j + dc[ii];
								if (nr < 1 || nc < 1 || nr > n || nc > n) continue;
								v[nr][nc].push_back(1);
							}
						}
					}
				}
			}
		}

		//겨울
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				grd[i][j] += igr[i][j];
			}
		}
	}
	ll cnt = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if (v[i][j].size() > 0) cnt += v[i][j].size();
		}
	}
	cout << cnt;
	return 0;
}

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

 

16234번: 인구 이동

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모든 나라는 1×1 크기이기 때문에, 모든 국경선은 정사각형 형태이다. 오늘부터 인구 이동이 시작되는 날이다. 인구 이동은 다음과 같이 진행되고, 더 이상 아래 방법에 의해 인구 이동이 없을 때까지 지속된다. 국경선을 공유하는 두 나라의 인구 차이가 L명

www.acmicpc.net

bfs 혹은 dfs를 활용하여 해결할 수 있다.

 

인구이동 조건과, 방문 여부가 탐색 진행의 기준이 된다.

 

for(for(bfs)) 구조로 해결할 수 있다.

 

for(for 을 완전히 탈출할 때 까지가 한 번의 인구이동 날이라고 할 수 있다.

 

따라서 이를 무한루프로 감싸서, 인구의 이동이 없는 경우 무한루프를 탈출하는 구조로 해결하면 된다.

 

 

그런데, 인구 이동 조건을 만족하더라도, 그 자리에서 인구수를 바로 갱신할 수가 없다.

 

일단 국경을 개방할 수 있는 지점을 모두 찾아내야 하기 때문에, 일단 한 번의 bfs가 다 종료되어야 인구수를 갱신할 수 있다. 방문처리된 지점들(큐에 삽입된 적이 있는 지점들)이 갱신의 대상이기 때문에, 이 좌표들을 차례로 백터에 저장해준다.

 

이후에 벡터의 크기가 연합국의 숫자이고, 인구수의 합은 큐에 삽입하면서 기억해 둘 것이다.

 

한번의 인구 이동이 모두 끝났는데, 변화가 없다면 무한 루프를 종료하고, 그렇지 않다면 방문처리 배열을 초기화해준 이후에 인구이동을 다시 시작해주면 된다.

 

#include<iostream>
#include<queue>
#include<math.h>
#include<vector>
using namespace std;
int N, L, R, m[51][51];
bool bor[51][51]; //방문 처리 배열
int dr[4] = { 0, 0, 1, -1 };
int dc[4] = { 1, -1, 0, 0 };

queue<pair<int, int> > q;
bool updated = false;
int idxSum = 0;
vector<pair<int, int> > v;
void bfs(pair<int, int> start) {
	q.push(start);
	bor[start.first][start.second] = true;

	while (!q.empty()) {
		pair<int, int> cur = q.front();
		q.pop();
		
		for (int i = 0; i < 4; i++) {
			int nr = cur.first + dr[i];
			int nc = cur.second + dc[i];
			if (nr < 0 || nc < 0 || nr >= N || nc >= N || bor[nr][nc])
				continue;
			if (abs(m[nr][nc] - m[cur.first][cur.second]) >= L &&
				abs(m[nr][nc] - m[cur.first][cur.second]) <= R) {
				q.push({ nr, nc });
				bor[nr][nc] = true; 
				
				v.push_back({ nr, nc });
				idxSum += m[nr][nc];
			}
		}
	}
}
void init() {
	for (int i = 0; i < N; i++) 
		for (int j = 0; j < N; j++) 
			bor[i][j] = 0;
}
int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> N >> L >> R;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			cin >> m[i][j];

	int res = 0;
	while (1) {
		updated = false;
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (!bor[i][j]) {
					v.clear();
					v.push_back({ i,j }); 
					idxSum = m[i][j];
					bfs({ i, j });
				}
				//열린 국경이 있으면
				if (v.size() >= 2) { //한 연합 내의 국가 개수
					updated = true;
					int val = idxSum / v.size();
					for (int i = 0; i < v.size(); i++) {
						m[v[i].first][v[i].second] = val;
					}
				}
			}
		}
		if (updated) res++;
		else break;
		init();
	}
	cout << res << '\n';
	return 0;
}

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

 

17281번: ⚾

⚾는 9명으로 이루어진 두 팀이 공격과 수비를 번갈아 하는 게임이다. 하나의 이닝은 공격과 수비로 이루어져 있고, 총 N이닝동안 게임을 진행해야 한다. 한 이닝에 3아웃이 발생하면 이닝이 종료되고, 두 팀이 공격과 수비를 서로 바꾼다. 두 팀은 경기가 시작하기 전까지 타순(타자가 타석에 서는 순서)을 정해야 하고, 경기 중에는 타순을 변경할 수 없다. 9번 타자까지 공을 쳤는데 3아웃이 발생하지 않은 상태면 이닝은 끝나지 않고, 1번 타자가 다시 타석에

www.acmicpc.net

선수 9명의 순서를 결정해야 한다. 4번 타자는 1번 선수로 고정되어 있기 때문에 이를 반영해준다.

 

이닝별로 선수들의 결과를 입력으로 받는다.

 

따라서 모든 순열을 구해서 선수들의 순서를 만들어낸 이후에, 야구의 조건을 구현해주면 된다.

 

 

1루, 2루 등에 진출해 있는 선수들에 대한 관리는, 선수 번호를 그대로 인덱스로 해서 배열을 두었다.

 

1이면 1루에 있다는 뜻이고, 2면 2루 3이면 3루에, 

4 이상이 되면 홈으로 들어왔다는 의미이다.

 

각 이닝별로 선수들의 수행을 그대로 따라가면서 시뮬레이션을 진행해주면 된다.

 

res[][] 배열은 이닝별 선수의 득점이다.

 

num은 1~9까지 선수들 중에 9명을 뽑는 경우의 수로 사용한다.

 

ord는 뽑아서 결정된 선수들의 순서이다. ord[i]는 i번 타자를 의미한다.

 

#include<iostream> //2백만
#include<vector>
using namespace std;
int n, res[52][10], num[10], ord[10], pos[10], Max = -1;
bool isused[10];
void play() {
	int hitter = 1, score = 0;
	for (int i = 1; i <= n; i++) { //i이닝에
		int outCnt = 0;

		while (1) {
			if (res[i][ord[hitter]] == 0) { //아웃인 경우
				hitter++;
				if (hitter >= 10) hitter = 1;
				outCnt++;
				if (outCnt == 3) {
					//이닝 교체
					for (int j = 1; j <= 9; j++) pos[j] = 0;
					break;
				}
			}
			else {
				//득점타
				for (int j = 1; j <= 9; j++) {
					if (pos[j] > 0 || j == ord[hitter]) { //타석에 나가 있는 선수라면
						pos[j] += res[i][ord[hitter]];
						if (pos[j] >= 4) {
							//홈에 들어오면
							pos[j] = 0;
							score++;
						}
					}
				}
				hitter++;
				if (hitter >= 10) hitter = 1;
			}
		}
	}
	if (Max < score) Max = score;
}
void func(int k) {
	if (k > 9) { //base condition
		play();
		return;
	}
	for (int i = 2; i <= 9; i++) {
		if (!isused[i]) {
			ord[k] = i;
			isused[i] = true;
			if (k == 3) func(k + 2); //3번엔 다음 4번이 아니라 5번을 정함
			else func(k + 1);
			isused[i] = false;
		}
	}
}
int main(void) {
	for (int i = 1; i <= 9; i++)
		num[i] = i;
	isused[1] = true; //1은 항상 사용중
	ord[4] = 1; // 4번 선수는 항상 1
	cin >> n;
	
	for (int i = 1; i <= n; i++) 
		for (int j = 1; j <= 9; j++) 
			cin >> res[i][j];
	
	func(1);
	cout << Max << '\n';
	return 0;
}

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

 

17144번: 미세먼지 안녕!

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사과는 뛰어난 코딩 실력을 이용해 각 칸 (r, c)에 있는 미세먼지의 양을 실시간으로 모니터링하는 시스템을 개발했다. (r, c)는 r행 c열을 의미한다. 공기청정기는 항상 왼쪽 열에 설치되어 있고, 크기는 두 행을 차지한다. 공기청정기가 설치되어 있지 않은 칸에는 미세먼

www.acmicpc.net

 

약간의 bfs와 시뮬레이션이 혼합된 문제이다.

 

입력을 받은 이후에, 먼지가 있는 곳을 미리 큐에 넣어준다. 동시에 확산되어야 한다는 조건이 있기 때문이다.

 

미리 큐에 넣어주고, 한 번 탐색을 했을 때 큐의 크기만큼만 확산을 진행하면 단위 시간이 흘렀다고 볼 수 있다.

 

그리고, 이전에 발생했던 먼지의 확산이, 앞으로 발생하게 될 먼지의 확산에 영향을 끼치지 않게 하기 위해서

 

변화량을 따로 저장한 이후에, 확산을 마치고 변화량을 모두 구한 이후에 한꺼번에 반영해줘야 한다.

 

그렇지 않으면 동시에 확산했다는 조건을 만족시킬 수 없기 때문이다.

 

 

다음으로 환기에 대한 조건을 구현할 때는, 조건에 맞게 인덱스를 가지고 놀아주면 된다.

 

한 가지 주의할 사항은, 환기의 순서를 신경 써야 한다는 것이다.

 

먼저 빨려들어가서 없어지는 먼지의 값을 덮어 씌워주는 방향으로 순서를 정해야, 중간에 다른 구석 지점에서 먼지의 값이 누락되는 것을 방지할 수 있다.

 

따라서 먼저 빨려들어가는 쪽에 대한 처리를 먼저 해주는 방식으로 구현한다.

 

#include<iostream>
#include<queue>
using namespace std;
int m[52][52], T, R, C, dif[52][52];
bool vis[52][52];
pair<int, int> Up;
pair<int, int> Dn;
queue<pair<int, int> > q;
int dr[4] = { 0,0,1,-1 };
int dc[4] = { 1,-1,0,0 };
void clean() {
	//상부
	for (int i = 1; i <= Up.first - 1; i++)  //하향
		m[Up.first - i][0] = m[Up.first - 1 - i][0];
	for (int i = 0; i <= C - 2; i++) //좌향
		m[0][i] = m[0][i + 1];
	for (int i = 0; i <= Up.first - 1; i++) //상향
		m[i][C - 1] = m[i + 1][C - 1];
	for (int i = C - 1; i >= 1; i--) //우향
		m[Up.first][i] = m[Up.first][i - 1];


	//하부
	for (int i = Dn.first + 1; i <= R - 2; i++) //상향
		m[i][0] = m[i + 1][0];
	for (int i = 1; i <= C - 1; i++) //좌향
		m[R - 1][i - 1] = m[R - 1][i];
	for (int i = R - 1; i >= Dn.first + 1; i--)//하향
		m[i][C - 1] = m[i - 1][C - 1];

	for (int i = C - 1; i >= 1; i--) //우향
		m[Dn.first][i] = m[Dn.first][i - 1];
}

void bfs() {
	int cnt = q.size();
	while (cnt--) {
		pair<int, int> cur = q.front();
		q.pop();
		for (int i = 0; i < 4; i++) {
			int nr = cur.first + dr[i];
			int nc = cur.second + dc[i];
			if (nr < 0 || nc < 0 || nr >= R || nc >= C ) continue;
			if (nr == Up.first && nc == Up.second) continue;
			if (nr == Dn.first && nc == Dn.second) continue;
			
			dif[cur.first][cur.second] -= m[cur.first][cur.second] / 5;
			dif[nr][nc] += m[cur.first][cur.second] / 5;
		}
	}
	//update
	for (int i = 0; i < R; i++) {
		for (int j = 0; j < C; j++) {
			m[i][j] += dif[i][j];
		}
	}
	//Print();
	clean();
}
void init() {
	for (int i = 0; i < R; i++) {
		for (int j = 0; j < C; j++) {
			vis[i][j] = false;
			dif[i][j] = 0;
		}
	}
}
int main(void) {
	cin >> R >> C >> T;
	bool fst = true;
	for (int i = 0; i < R; i++) {
		for (int j = 0; j < C; j++) {
			cin >> m[i][j];
			if (m[i][j] == -1) {
				m[i][j] = 0;
				if (fst) {
					Up.first = i;
					Up.second = j;
					fst = false;
				}
				else {
					Dn.first = i;
					Dn.second = j;
				}
			}
		}
	}
	
	//1초 루틴
	while (T--) {
		for (int i = 0; i < R; i++) {
			for (int j = 0; j < C; j++) {
				if (m[i][j] != 0 && !vis[i][j]) { //방문 조건도 사실 필요없음
					q.push({ i, j });
					vis[i][j] = true;
				}
			}
		}
		bfs();
		init();
	}
	int Sum = 0;
	for (int i = 0; i < R; i++)
		for (int j = 0; j < C; j++)
			Sum += m[i][j];
	cout << Sum << '\n';
	return 0;
}

C++ 기준

 

1. 배열의 크기를 벗어나서 index에 접근하는 경우

 

2. 전역 변수들의 메모리 크기 총합이 메모리 제한을 초과하는 경우

 

3. 지역 변수들을 메모리 크기 총합이 스택 메모리 제한을 초과하는 경우

 

4. 재귀 호출이 너무 깊어지는 경우

 

5. 0으로 나누는 경우

 

6. main 함수가 0이 아닌 다른 값을 반환하는 경우

'알고리즘 문제 풀이 > 문제 접근 방법' 카테고리의 다른 글

다익스트라 - 함께여행  (0) 2022.11.18
시간 줄이기  (0) 2019.08.20
메모리초과  (0) 2019.08.16
배열 최대/최소 기억  (0) 2019.07.09
투포인터 응용  (0) 2019.07.09

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

 

13335번: 트럭

문제 강을 가로지르는 하나의 차선으로 된 다리가 하나 있다. 이 다리를 n 개의 트럭이 건너가려고 한다. 트럭의 순서는 바꿀 수 없으며, 트럭의 무게는 서로 같지 않을 수 있다. 다리 위에는 단지 w 대의 트럭만 동시에 올라갈 수 있다. 다리의 길이는 w 단위길이(unit distance)이며, 각 트럭들은 하나의 단위시간(unit time)에 하나의 단위길이만큼만 이동할 수 있다고 가정한다. 동시에 다리 위에 올라가 있는 트럭들의 무게의 합은 다리의 최

www.acmicpc.net

 

다리의 상태와 트럭의 상태를 나타내야 한다.

 

다리의 경우, 지금 버티고 있는 무게가 몇인지 그리고 현재 다리 위에 몇 개의 트럭이 올라와 있는지를 항상 유지해야 한다.

 

트럭의 경우에는, 각 트럭 별로 트럭의 무게, 그리고 다리 위에 있는지 여부, 그리고 다리 위에 존재한 시간(혹은 거리)을 유지해야 한다.

 

따라서 위와 같은 조건을 나타내기 위해서 구조체를 사용했다.

 

무한 루프를 만들고, 마지막 차가 다리를 탈출하는 순간을 루프 탈출 조건으로 잡았다.

 

#include<iostream>
using namespace std;
struct Bridge { 
	int wei = 0; //다리에 가해진 무게
	int cnt = 0; //다리위 차의 개수
};
struct Car {
	int wei = 0; //차의 무게
	int time = 0;//차의 이동 시간(거리)
	bool onBri = false; //차가 다리위에 있는지 여부
};
Car car[2000];
Bridge brg;
int n, len, lim; //차의 개수, 다리의 길이, 하중 제한
int main(void) {
	cin >> n >> len >> lim;
	for (int i = 0; i < n; i++)
		cin >> car[i].wei;
	brg.cnt = 0;
	brg.wei = 0;
	int idx = 0, Time = 0; //다리위에 올라가는 차의 인덱스, 전체 시간
	bool endFlag = false;
	while (1) {
	
		//다리 위의 차들 이동(시간 증가)
		for (int i = 0; i < n; i++) {
			if (car[i].onBri) {
				car[i].time++;
				//printf("%d번 차 움직인 거리: %d\n", i, car[i].time);
				if (car[i].time >= len) {
					if (i == n - 1) {
						//다리를 벗어나는 차가 마지막 차라면
						endFlag = true;
						Time++;
						break;
					}
					//이 차가 다리를 다 건너면
					brg.cnt--;
					brg.wei = brg.wei - car[i].wei;
					car[i].onBri = false;
				}
			}
		}

		if (endFlag) break;

		if (lim - brg.wei >= car[idx].wei && brg.cnt < len) {
			//가능한 무게이면서 다리위에 공간이 남았으면
			car[idx].onBri = true;
			brg.wei = brg.wei + car[idx].wei;
			idx++;
			brg.cnt++;
		}
		Time++;
	}
	cout << Time << '\n';
	return 0;
}

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

 

5014번: 스타트링크

문제 강호는 코딩 교육을 하는 스타트업 스타트링크에 지원했다. 오늘은 강호의 면접날이다. 하지만, 늦잠을 잔 강호는 스타트링크가 있는 건물에 늦게 도착하고 말았다. 스타트링크는 총 F층으로 이루어진 고층 건물에 사무실이 있고, 스타트링크가 있는 곳의 위치는 G층이다. 강호가 지금 있는 곳은 S층이고, 이제 엘리베이터를 타고 G층으로 이동하려고 한다. 보통 엘리베이터에는 어떤 층으로 이동할 수 있는 버튼이 있지만, 강호가 탄 엘리베이터는 버튼이 2개밖에 없

www.acmicpc.net

 

1차원에서 최단거리를 구하는 문제이고, 가중치가 없기 때문에 bfs를 활용해주면 된다.

 

움직임 배열을 입력받는 U와 D로 정해주고, 시작점을 큐에 넣은 이후에, 하나씩 pop 해서 확인해주면 된다.

 

#include<iostream>
#include<queue>
using namespace std;
int n, src, des, Up, Down;
int dis[1000001]; //1 indexed
int Move[2];
queue<int> q;
void bfs(int start) {
	q.push(start);
	dis[start]++;
	while (!q.empty()) {
		int cur = q.front();
		q.pop();
		for (int i = 0; i < 2; i++) {
			int nf = cur + Move[i];
			if (nf < 1 || nf > n || dis[nf] >= 0) continue;
			q.push(nf);
			dis[nf] = dis[cur] + 1;
		}
	}
}
int main(void) {
	
	cin >> n >> src >> des >> Up >> Down;
	for (int i = 1; i <= n; i++)
		dis[i] = -1;
	Move[0] = Up;
	Move[1] = Down * -1;
	bfs(src);
	if (dis[des] == -1) cout << "use the stairs\n";
	else
		cout << dis[des] << '\n';
	return 0;
}

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

 

14499번: 주사위 굴리기

첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다. 둘째 줄부터 N개의 줄에 지도에 쓰여 있는 수가 북쪽부터 남쪽으로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 주사위를 놓은 칸에 쓰여 있는 수는 항상 0이다. 지도의 각 칸에 쓰여 있는 수는 10을 넘지 않는 자연수 또는 0이다. 마

www.acmicpc.net

먼저 주사위의 동, 서, 남, 북, 위, 아래를 배열 인덱스의 0~5까지로 대응시킨다.

 

명령을 하나씩 받아서, 먼저 이동할 수 있는지 판단한다. 동쪽이면 동쪽으로 벗어날 것이고, 남쪽이면 남쪽으로 벗어날 것이고 이런 식으로 확인할 수 있다.

 

지도를 벗어나지 않는다면, 명령에 맞춰서 주사위를 회전해주면 된다. 회전 방향에 따라 주사위의 상태를 갱신해주고, 주사위의 위치를 변경해준다.

 

이후에 조건에 맞게 출력을 해주면 된다.

 

#include<iostream>
using namespace std;
int dice[6];
int Row, Col, srcR, srcC, cnt, m[20][20];
void Move(int dir) {
	int temp;
	if (dir == 1) { //동쪽으로 굴릴 때
		if (srcC + 1>= Col) return;
		//주사위 회전, 좌표 이동
		//남2 북3 그대로
		temp = dice[0];
		dice[0] = dice[4];
		dice[4] = dice[1];
		dice[1] = dice[5];
		dice[5] = temp;
		srcC++;
	}
	else if (dir == 2) { //서
		if (srcC - 1 < 0) return;
		temp = dice[1];
		dice[1] = dice[4];
		dice[4] = dice[0];
		dice[0] = dice[5];
		dice[5] = temp;
		srcC--;
	}
	else if (dir == 3) { //북
		if (srcR - 1 < 0) return;
		temp = dice[3];
		dice[3] = dice[4];
		dice[4] = dice[2];
		dice[2] = dice[5];
		dice[5] = temp;
		srcR--;
	}
	else { //남
		if (srcR + 1 >= Row) return;
		temp = dice[2];
		dice[2] = dice[4];
		dice[4] = dice[3];
		dice[3] = dice[5];
		dice[5] = temp;
		srcR++;
	}
	if (m[srcR][srcC] == 0) {
		m[srcR][srcC] = dice[5];
	}
	else {
		dice[5] = m[srcR][srcC];
		m[srcR][srcC] = 0;
	}
	cout << dice[4] << '\n';
}
int main(void) {
	
	cin >> Row >> Col >> srcR >> srcC >> cnt;
	for (int i = 0; i < Row; i++) {
		for (int j = 0; j < Col; j++) {
			cin >> m[i][j];
		}
	}
	while (cnt--) {
		int op;
		cin >> op;
		Move(op);
	}
	return 0;
}

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

 

1547번: 공

첫째 줄에 컵의 위치를 바꾼 횟수 M이 주어지며, M은 50보다 작거나 같은 자연수이다. 둘째 줄부터 M개의 줄에는 컵의 위치를 바꾼 방법 X와 Y가 주어지며, X번 컵과 Y번 컵의 위치를 서로 바꾸는 것을 의미한다. 컵을 이동시키는 중에 공이 컵에서 빠져나오는 경우는 없다. X와 Y의 값은 3보다 작거나 같고, X와 Y가 같을 수도 있다.

www.acmicpc.net

arr[0]에 공이 있다고 정해둔다.

 

arr에 1,2,3을 초기에 순서대로 담아두고, 값이 컵의 번호라고 생각하고 들어오는 숫자의 인덱스를 구해서 두 인덱스에 해당하는 arr값을 스왑해준다.

 

#include<iostream>
using namespace std;
int m, arr[3] = { 1,2,3 };
int main(void) {
	cin >> m;

	while (m--) {
		int num1, num2, idx1, idx2;
		cin >> num1 >> num2;
		for (int i = 0; i < 3; i++) {
			if (arr[i] == num1) idx1 = i;
			if (arr[i] == num2) idx2 = i;
		}
	
		int temp = 0;
		temp = arr[idx1];
		arr[idx1] = arr[idx2];
		arr[idx2] = temp;
	}
	cout << arr[0] << '\n';

	return 0;
}

+ Recent posts