2022. 5. 11. 22:05ㆍTIL💡/Algorithms
💚 16928 뱀과 사다리 게임
- 100개의 칸으로 나누어져 있는 게임이 있다. 1에서 100으로 가야 한다.
- 주사위를 굴려 나온 수만큼 이동할 수 있으며, 도착한 카이 사다리인 경우에는 사다리를 타고 더 큰 번호의 칸으로, 뱀인 경우에는 더 작은 번호의 칸으로 이동한다.
- 주사위에 나온 수를 정할 수 있을 때, 최소 몇 번 굴려야 하는지 구하는 문제
- 게임에서 뱀과 사다리의 구분은 중요하지만 구현에서는 별로 중요하지 않다.
- x ➡️ y로 간다는 점만 중요하다.
- 새로운 배열 next[x]를 만들어서, x에 도착한 이후에 가야할 곳을 모두 기록
- 뱀이나 사다리인 경우에는
next[x] = y
- 일반 칸인 경우에는
next[x] = x
#include <iostream>
#include <algorithm>
#include <queue>
#define next _next
using namespace std;
// 1로부터의 거리 저장
int dist[101];
// next[i]: i에 도착한 이후에 가야하는 곳 저장
int next[101];
int main() {
int n, m;
cin >> n >> m;
for(int i = 1;i <= 100;i++) {
next[i] = i;
dist[i] = -1;
}
while(n--) {
int x, y;
cin >> x >> y;
next[x] = y;
}
while(m--) {
int x, y;
cin >> x >> y;
next[x] = y;
}
dist[1] = 0;
queue<int> q;
q.push(1);
while(!q.empty()) {
int x = q.front();
q.pop();
// 주사위 돌리기
for(int i = 1;i <= 6;i++) {
int y = x + i;
if(y > 100) continue;
y = next[y];
if(dist[y] == -1) {
dist[y] = dist[x] + 1;
q.push(y);
}
}
}
cout <<dist[100] << '\n';
return 0;
}
💚 169489 데스 나이트
- 데스나이트는 (r, c)에서 (r - 2, c - 1), (r - 2, c + 1), (r, c - 2), (r, c + 2), (r + 2, c - 1), (r + 2, c + 1)로 이동할 수 있는 말이다.
- 크기가 N * N인 체스판과 두 칸 (r1, c1), (r2, c2)가 주어졌을 때, (r1, c1)에서 (r2, c2)로 가는 최소 이동 횟수를 구하는 문제
- 5 <= N <= 200
💚 9019 DSLR
- 이 문제는 최소값을 구해야하는 건 맞지만
- 어떠한 과정을 거쳐야하는지를 구해야 한다.
- 배열을 하나 더 이용해서 어떤 과정을 거쳤는지를 저장해야 한다.
- how[i] = i를 어떻게 만들었는지
-대신 모두 기록하면 너무 많은 공간을 차지하기 때문에 안됨
재귀로도 푸는 방법이 있다.
#include <iostream>
void print(int A, int B){
if(A == B) return;
print(A, from[B]);
cout << how[B];
}
이전의 내 BFS 풀이
결과물과 결과물을 만든 명령어를 함께 Queue에 입력한다.
그리고 방문된 적 없는 숫자만 확장해나간다는 특징이 있다.
#include <iostream>
#include <queue>
#include <string>
#include <cstring>
using namespace std;
const int MAX = 10000;
int visited[MAX];
string bfs(int a, int b);
int main(void){
int t;
int a, b;
cin >> t;
while(t--){
memset(visited,false,sizeof(visited));
cin >> a >> b;
cout << bfs(a,b) << endl;
}
}
string bfs(int a, int b){
int next;
int num;
string command;
queue<pair<int, string>> q;
q.push(make_pair(a, ""));
visited[a] = true;
while(!q.empty()){
num = q.front().first;
command = q.front().second;
q.pop();
if(b == num)
break;
//D
next = (num * 2) % MAX;
if(!visited[next]){
visited[next] = true;
q.push(make_pair(next,command+ "D"));
}
//S
next = (num - 1) < 0? 9999 : num -1;
if(!visited[next]){
visited[next] = true;
q.push(make_pair(next,command+ "S"));
}
//L
next = (num % 1000) * 10 + num / 1000;
if(!visited[next]){
visited[next] = true;
q.push(make_pair(next,command+ "L"));
}
//R
next = (num % 10) * 1000 + (num / 10);
if(!visited[next]){
visited[next] = true;
q.push(make_pair(next,command+ "R"));
}
}
return command;
}
💚 14502 연구소
문제를 아래와 같이 크게 2개로 나눌 수 있다.
벽을 3개 세워서(재귀로 조합 생성) / 바이러스가 퍼질 수 없는 곳의 크기(DFS or BFS)를 구하기
이 문제는 최소가 특징인 점이 아니기에 하나의 정점에서 모든 정점을 방문하는 DFS로도 풀 수 있다.
(DFS/BFS의 목적: 한 정점에서 시작해 연결된 모든 정점을 방문)
벽을 3개 세우는 경우의 수: (NM)^3
벽을 세운 다음 안전 영역의 크기를 구하는 방법: BFS / DFS로 O(NM)
총 O((NM)^4)가 나오는데, N,M <= 8이기 때문에 시간 안에 해결할 수 있다.
BFS
#include <iostream>
#include <queue>
using namespace std;
int n, m;
int a[10][10];
int b[10][10];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
bool inside(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m;
}
int bfs() {
queue<pair<int, int>> q;
for(int i = 0;i < n;i++) {
for(int j = 0;j < m;j++) {
b[i][j] = a[i][j];
if(b[i][j] == 2) {
q.push({i, j});
}
}
}
while(!q.empty()) {
int x = q.front().first;
int y = q.front().second;
q.pop();
for(int k = 0;k < 4;k++) {
int nx = x + dx[k];
int ny = y + dy[k];
if(inside(nx, ny) && b[nx][ny] == 0) {
b[nx][ny] = 2;
q.push({nx, ny});
}
}
}
int cnt = 0;
for(int i = 0;i < n;i++) {
for(int j = 0;j < m;j++) {
if(b[i][j] == 0) {
cnt++;
}
}
}
return cnt;
}
int main() {
cin >> n >> m;
for(int i = 0;i < n;i++){
for(int j = 0;j < m;j++) {
cin >> a[i][j];
}
}
int ans = 0;
for(int x1 = 0;x1 < n;x1++) {
for(int y1 = 0;y1 < m;y1++) {
if(a[x1][y1] != 0) continue;
for(int x2 = 0;x2 < n;x2++) {
for(int y2 = 0;y2 < m;y2++){
if(a[x2][y2] != 0) continue;
for(int x3 = 0;x3 < n;x3++) {
for(int y3 = 0;y3 < m;y3++) {
if(a[x3][y3] != 0) continue;
if(x1 == x2 && y1 == y2) continue;
if(x2 == x3 && y2 == y3) continue;
if(x1 == x3 && y1 == y3) continue;
a[x1][y1] = 1;
a[x2][y2] = 1;
a[x3][y3] = 1;
int cur = bfs();
if(cur > ans) ans = cur;
a[x1][y1] = 0;
a[x2][y2] = 0;
a[x3][y3] = 0;
}
}
}
}
}
}
cout << ans << '\n';
return 0;
}
DFS
#include <iostream>
#include <queue>
using namespace std;
int n, m;
int a[10][10];
int b[10][10];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
bool inside(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m;
}
void dfs(int x, int y) {
for(int k = 0;k < 4;k++) {
int nx = x + dx[k];
int ny = y + dy[k];
if(inside(nx, ny) && b[nx][ny] == 0) {
b[nx][ny] = 1;
dfs(nx, ny);
}
}
}
int dfs() {
for(int i = 0;i < n;i++) {
for(int j = 0;j < m;j++) {
b[i][j] = a[i][j];
}
}
for(int i = 0;i < n;i++) {
for(int j = 0;j < m;j++) {
if(b[i][j] == 2) {
dfs(i, j);
}
}
}
int cnt = 0;
for(int i = 0;i < n;i++) {
for(int j = 0;j < m;j++) {
if(b[i][j] == 0) {
cnt++;
}
}
}
return cnt;
}
int main() {
cin >> n >> m;
for(int i = 0;i < n;i++){
for(int j = 0;j < m;j++) {
cin >> a[i][j];
}
}
int ans = 0;
for(int x1 = 0;x1 < n;x1++) {
for(int y1 = 0;y1 < m;y1++) {
if(a[x1][y1] != 0) continue;
for(int x2 = 0;x2 < n;x2++) {
for(int y2 = 0;y2 < m;y2++){
if(a[x2][y2] != 0) continue;
for(int x3 = 0;x3 < n;x3++) {
for(int y3 = 0;y3 < m;y3++) {
if(a[x3][y3] != 0) continue;
if(x1 == x2 && y1 == y2) continue;
if(x2 == x3 && y2 == y3) continue;
if(x1 == x3 && y1 == y3) continue;
a[x1][y1] = 1;
a[x2][y2] = 1;
a[x3][y3] = 1;
int cur = dfs();
if(cur > ans) ans = cur;
a[x1][y1] = 0;
a[x2][y2] = 0;
a[x3][y3] = 0;
}
}
}
}
}
}
cout << ans << '\n';
return 0;
}
💚12886 돌 그룹
- 최소의 값을 구하는 것이 아니므로 DFS/BFS 모두 가능
- 전체 정점의 개수: A + B + C개 / A + B개(어차피 C = N - A - B이기 때문)
- 전체를 탐색하기에는 너무 경우의 수가 커진다.
#include <iostream>
#include <queue>
using namespace std;
bool check[1501][1501];
int sum;
// 가능한 구성인지
void go(int x, int y) {
// (x, y, sum - y - x) 조합은 이미 탐색됨
if(check[x][y]) return;
check[x][y] = true;
// 비교용
int a[3] = {x, y, sum - x - y};
for(int i = 0;i < 3;i++) {
for(int j = 0;j < 3;j++) {
// a[j]에서 a[i]로 전달
if(a[i] < a[j]) {
int b[3] = {x, y, sum - x - y};
b[i] += a[i];
b[j] -= a[i];
go(b[0], b[1]);
}
}
}
}
int main() {
int x, y, z;
cin >> x >> y >> z;
sum = x + y + z;
// 불가능한 조건
if(sum % 3 != 0) {
cout << 0 << '\n';
return 0;
}
go(x, y);
if(check[sum / 3][sum / 3]) {
cout << 1 << '\n';
} else {
cout << 0 << '\n';
}
return 0;
}
💚2206 벽 부수고 이동하기
- N * M의 행렬로 나타내는 지도에서 (1, 1)에서 (N, M)으로 최단 거리로 이동하는 문제
- 0은 빈칸, 1은 벽
- 벽은 한 번 부수고 지나갈 수 있다는 점에서 여기에서 정점은 단순히 r, c 뿐만 아니라 k라는 벽을 부순 횟수를 따로 저장해야 한다.
- 이전에 구슬 던지기 문제와 유사하게 Queue에 여러개의 정보를 저장하기 위해 tuple을 사용한다.
#include <iostream>
#include <queue>
// 순서대로 정리
#include <tuple>
using namespace std;
// map
int a[1000][1000];
// r, c, k(벽 부순 유무)
int d[1000][1000][2];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
int n, m;
bool inside(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m;
}
int main() {
scanf("%d %d", &n, &m);
for(int i = 0;i < n;i++) {
for(int j = 0;j < m;j++) {
scanf("%1d", &a[i][j]);
}
}
queue<tuple<int, int, int>> q;
d[0][0][0] = 1;
q.push({0,0,0});
while(!q.empty()) {
int x, y, z;
tie(x, y, z) = q.front();
q.pop();
for(int k = 0;k < 4;k++) {
int nx = x + dx[k];
int ny = y + dy[k];
if(!inside(nx, ny)) continue;
// 빈칸이고 방문한 적도 없는 칸
if(a[nx][ny] == 0 && d[nx][ny][z] == 0) {
// 이동 기록
d[nx][ny][z] = d[x][y][z] + 1;
q.push(make_tuple(nx, ny, z));
}
// 아직 벽을 부순 적이 없고 빈칸이 아니고 방문한 적도 없는 칸
if(z == 0 && a[nx][ny] == 1 && d[nx][ny][z + 1] == 0) {
d[nx][ny][z + 1] = d[x][y][z] + 1;
q.push(make_tuple(nx, ny, z + 1));
}
}
}
// 벽을 부수고도, 부수지 않고도 통과
if(d[n - 1][m - 1][0] != 0 && d[n - 1][m - 1][1] != 0) {
cout << min(d[n - 1][m - 1][0], d[n - 1][m - 1][1]);
}
else if(d[n - 1][m - 1][0] != 0) {
cout << d[n - 1][m - 1][0];
}
else if(d[n - 1][m - 1][1] != 0) {
cout << d[n - 1][m - 1][1];
} else {
cout << -1;
}
return 0;
}
💚16946 벽 부수고 이동하기4
앞 문제보다 살짝 더 복잡하다.
문제가 말한 그대로 지금 위치에서 벽을 부수고 매번 이동할 수 있는 칸의 수를 세면 지나치게 비효율적이다.
N, M <= 1000이므로 (1000 * 1000)^2으로 1조 정도의 경우의수를 탐색해야 한다.
이동할 수 있는 빈칸을 모두 그룹 짓는다.
그리고 근처의 빈칸 그룹을 탐색한 후 그룹의 크기+ 1(현재 벽인 칸)이 매번 이동할 수 있는 칸의 수가 나온다.
이렇게 진행하면 빈칸 그룹을 찾는 데 O(NM) + 근처의 그룹을 찾는 데 O(NM) = O(NM)이라는 시간 복잡도가 나온다.
#include <iostream>
#include <queue>
#include <set>
#include <tuple>
using namespace std;
int n, m;
// 벽, 빈 칸 표시
int a[1000][1000];
// 방문 여부
int check[1000][1000];
// 소속 그룹
int group[1000][1000];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
vector<int> group_size;
bool inside(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m;
}
void bfs(int sx, int sy) {
queue<pair<int, int>> q;
int g = group_size.size();
// 초기 세팅
int cnt = 1;
q.push({sx, sy});
check[sx][sy] = true;
// 새로운 그룹의 시작
group[sx][sy] = g;
while(!q.empty()) {
int x, y;
tie(x, y) = q.front();
q.pop();
for(int k = 0;k < 4;k++) {
int nx = x + dx[k];
int ny = y + dy[k];
if(!inside(nx, ny)) continue;
if(a[nx][ny] == 0 && check[nx][ny] == false) {
check[nx][ny] = true;
q.push({nx, ny});
group[nx][ny] = g;
cnt++;
}
}
}
group_size.push_back(cnt);
}
int main() {
cin >> n >> m;
for(int i = 0;i < n;i++) {
string s;
cin >> s;
for(int j = 0;j < m;j++) {
a[i][j] = s[j] - '0';
check[i][j] = false;
group[i][j] = -1;
}
}
// 그룹 생성
for(int i = 0;i < n;i++) {
for(int j = 0;j < m;j++) {
if(a[i][j] == 0 && check[i][j] == false) {
bfs(i, j);
}
}
}
for(int i = 0;i < n;i++) {
for(int j = 0;j < m;j++) {
if(a[i][j] == 0)
cout << 0;
else {
set<int> near;
for(int k = 0;k < 4;k++) {
int x = i + dx[k];
int y = j + dy[k];
if(!inside(x, y)) continue;
// 주변에 빈 칸이 있으면 해당 그룹을 set에 추가
if(a[x][y] == 0) near.insert(group[x][y]);
}
int ans = 1;
for(int g : near){
ans += group_size[g];
}
cout << ans % 10;
}
}
cout << '\n';
}
return 0;
}
💚16942 벽 부수고 이동하기2
- N *M의 행렬로 나타내는 지도에서 (1, 1)에서 (N, M)으로 최단 거리로 이동하는 문제
- 0은 빈칸, 1은 벽
- 단 벽은 K번까지 부수고 지나갈 수 있다.
💚16933 벽 부수고 이동하기3
- N *M의 행렬로 나타내는 지도에서 (1, 1)에서 (N, M)으로 최단 거리로 이동하는 문제
- 0은 빈칸, 1은 벽
- 이동할 때마다 낮과 밤이 바뀐다
- 단 벽은 K번까지 부수고 지나갈 수 있고, 낮에만 부술 수 있다.
즉 이제는 낮, 밤도 기록해야 한다.
💚16954 움직이는 미로 탈출
헷갈리지 않게 초마다 미로를 만든다.
8초까지만 벽을 준비하면 된다. 8초 이후에는 벽이 모두 사라지기 때문이다.
만약 각각 미로를 만들기 싫으면 A[r -t][c]로 빈칸인지, 벽인지 파악 가능하다.
#include <iostream>
#include <vector>
#include <queue>
#include <tuple>
using namespace std;
bool check[8][8][9];
// 제자리 이동도 포함
int dx[] = {0, 0, -1, 1, -1, 1, 1, -1, 0};
int dy[] = {-1, 1, 0, 0,-1, 1, -1, 1,0};
int n = 8;
bool inside(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < n;
}
int main() {
vector<string> a(n);
for(int i = 0;i < n;i++) {
cin >> a[i];
}
queue<tuple<int, int, int>> q;
check[7][0][0] = true;
q.push({7, 0, 0});
bool ans = false;
while(!q.empty()) {
int x, y, t;
tie(x, y, t) = q.front();
q.pop();
if(x == 0 && y == 7) ans = true;
for(int k = 0;k < 9;k++) {
int nx = x + dx[k];
int ny = y + dy[k];
// 8초 이후에는 벽이 모두 사라지기 때문
int nt = min(t + 1, 8);
if(inside(nx, ny)) {
// 현재 nx에 있는 위치의 칸의 t초 전 위치를 통해 벽이 내려올지 파악
if(nx - t >= 0 && a[nx - t][ny] == '#') continue;
// 현재 nx에 있는 위치의 칸의 (t + 1)초 전 위치를 통해 벽이 내려올지 파악
if(nx - t - 1 >= 0 && a[nx - t - 1][ny] == '#') continue;
if(check[nx][ny][nt] == false) {
// 방문 표시
check[nx][ny][nt] = true;
q.push({nx, ny, nt});
}
}
}
}
cout << (ans ? 1 : 0) << '\n';
return 0;
}
✅ 3055 탈출
먼저 물이 언제 차는지 미리 구해놓은 다음에 고슴도치를 그 다음에 이동시킨다.
위 움직이는 미로와 상당히 유사한 문제다.
시간이 촉박해서 이건 패스하였다.
✅ 16236 아기상어
거리가 가장 가까운 물고리를 찾을 때, 즉 지나야하는 칸의 개수의 최소값을 구할 때 BFS를 써야한다.
BFS마다 O(N^2)이라는 시간 복잡도가 소요된다.
그러한 BFS를 최대 O(N^2) 반복한다.
#include <iostream>
#include <vector>
#include <queue>
#include <tuple>
#include <algorithm>
using namespace std;
int dx[] = {0,0, 1, -1};
int dy[] = {1, -1, 0,0};
int n;
bool inside(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < n;
}
tuple<int, int, int> bfs(vector<vector<int>> &a, int sx, int sy, int size) {
// 먹을 수 있는 물고기의 소요 거리, x좌표, y좌표 저장
vector<tuple<int, int, int>> ans;
// 거리 기록을 위해 -1로 초기화
vector<vector<int>> d(n, vector<int>(n, -1));
queue<pair<int, int>> q;
q.push({sx, sy});
d[sx][sy] = 0;
while(!q.empty()) {
int x, y;
tie(x, y) =q.front();
q.pop();
for(int k = 0;k < 4;k++) {
int nx = x + dx[k];
int ny = y + dy[k];
// 배열 인덱스 및 중복 방문 확인
if(!inside(nx, ny) || d[nx][ny] != -1) continue;
bool moved = false;
bool eat = false;
// 아기 상어는 자신의 크기보다 큰 물고기가 있는 칸은 지나갈 수 없다.
// 그 외의 칸은 지나갈 수 있다.
if(a[nx][ny] == 0) moved = true;
else if(a[nx][ny] < size) {
moved = eat = true;
}
// 크기가 같은 물고기는 먹을 수는 없지만 그 물고기가 있는 칸은 지나갈 수 있다.
else if(a[nx][ny] == size) {
moved = true;
}
if(moved) {
q.push({nx, ny});
d[nx][ny] = d[x][y] + 1;
if(eat) {
ans.push_back({d[nx][ny], nx, ny});
}
}
}
}
if(ans.empty()) {
return make_tuple(-1, -1, -1);
}
// 만약 여러 개의 물고기를 먹을 수 있으면 가장 좌상단 물고기를 먹는다.
sort(ans.begin(), ans.end());
return ans[0];
}
int main() {
cin >> n;
vector<vector<int>> a(n, vector<int>(n, 0));
int x, y;
for(int i = 0;i < n;i++) {
for(int j = 0;j < n;j++) {
cin >> a[i][j];
// 아기 상어 위치 파악
if(a[i][j] == 9) {
tie(x, y) = make_pair(i, j);
a[i][j] = 0;
}
}
}
int ans = 0;
int size = 2;
int exp = 0;
while(true) {
int nx, ny, dist;
tie(dist, nx, ny) = bfs(a, x, y, size);
if(dist == -1) break;
a[nx][ny] = 0;
ans += dist;
exp += 1;
// 아기 상어가 자신의 크기와 같은 수의 물고기를 먹으면 크기가 1 증가
if(size == exp) {
size++;
exp = 0;
}
// 아기 상어 위치 갱신
tie(x, y) = make_pair(nx, ny);
}
cout << ans << '\n';
return 0;
}
💚6087 레이저 통신
거울을 설치한다는 것은 직선의 방향을 바꾸는 것이라고 볼 수 있다.
거울의 개수는 두 C를 연결하는 데 필요한 직선의 최소 개수 - 1
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <tuple>
using namespace std;
int n, m;
int dx[] = {0, 0, -1, 1};
int dy[] = {-1, 1, 0, 0};
bool inside(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m;
}
int main() {
cin >> m >> n;
vector<string> a(n);
int sx, sy, ex, ey;
sx = sy = ex = ey = -1;
for(int i = 0;i < n;i++){
cin >> a[i];
for(int j = 0;j < m;j++){
if(a[i][j] == 'C') {
if(sx == -1) {
sx = i;
sy = j;
}
else {
ex = i;
ey = j;
}
}
}
}
vector<vector<int>> d(n, vector<int>(m, -1));
queue<pair<int, int>> q;
d[sx][sy] = 0;
q.push({sx, sy});
while(!q.empty()) {
int x, y;
tie(x, y) = q.front();
q.pop();
for(int k = 0;k < 4;k++) {
int nx = x + dx[k];
int ny = y + dy[k];
while(inside(nx, ny)) {
// 벽에 부딪히면 종료
if(a[nx][ny] == '*') break;
if(d[nx][ny] == -1) {
// 방문 표시 겸 꺾는 횟수 표시
// 이전 방향 전환 횟수 + 1 기록
d[nx][ny] = d[x][y] + 1;
q.push({nx, ny});
}
nx += dx[k];
ny += dy[k];
}
}
}
cout << d[ex][ey] - 1 << '\n';
return 0;
}
💚1963 소수 경로
에라토스테네스의 체를 활용해 소수 판별을 한다.
그리고 필요한 변환의 수를 별도의 배열을 통해 기록해둔다.
#include <iostream>
#include <cstring>
#include <queue>
#include <string>
#include <algorithm>
using namespace std;
bool prime[10001];
bool c[10001];
int d[10001];
int change(int num, int index, int digit) {
// 맨 앞자리 0은 불가능
if(index == 0 && digit == 0) return -1;
string s = to_string(num);
s[index] = digit + '0';
return stoi(s);
}
int main() {
// 에라토스테네스의 체
for(int i = 2;i <= 10000;i++) {
if(prime[i] == false) {
for(int j = i * i;j <= 10000;j += i) {
prime[j] = true;
}
}
}
for(int i = 2;i <= 10000;i++) {
prime[i] = !prime[i];
}
int t;
cin >> t;
while(t--) {
int n, m;
cin >> n >> m;
memset(c, false, sizeof(c));
memset(d, 0, sizeof(d));
// 최초의 소수부터 시작
d[n] = 0;
c[n] = true;
queue<int> q;
q.push(n);
while(!q.empty()) {
int now = q.front();
q.pop();
for(int i = 0;i < 4;i++) {
for(int j = 0;j <= 9;j++) {
int next = change(now, i, j);
if(next != -1) {
if(prime[next] && c[next] == false) {
q.push(next);
d[next] = d[now] + 1;
c[next] = true;
}
}
}
}
}
cout << d[m] << '\n';
}
}
💚10026 적록색약
앞선 벽부수기 문제에서의 그룹짓기와 매우 유사한 문제다.
차이점은 알파벳이 다른 경우도 같은 그룹으로 처리해야한다는 점이다.
queue 밖에서 새로운 그룹이 시작되므로 queue에 처음으로 push할 때를 카운트하면 된다.
'TIL💡 > Algorithms' 카테고리의 다른 글
[백준] 11053 가장 긴 증가하는 부분 수열 (0) | 2022.05.12 |
---|---|
[프로그래머스] 정수 삼각형 (0) | 2022.05.12 |
[알고리즘 중급] 비트마스크 (0) | 2022.05.10 |
[알고리즘 중급] 재귀 - 2 (0) | 2022.05.10 |
[알고리즘 중급] 재귀 - 1 (0) | 2022.05.09 |