N x M 형태의 그래프가 주어집니다. 이때, 각 노드는 건물을 의미하고, 숫자는 방어력을 의미합니다. 방어력이 0 이하가 되면 건물은 파괴되고, 1 이상이면 건물은 생존합니다. 이때, 라운드를 거치면서 건물의 방어력을 회복하거나 공격하는 일이 벌어집니다.(건물이 파괴되어도 1 이상의 방어력으로 회복된다면 건물은 다시 생존하게 됩니다.) 라운드를 다 거친 후 생존한 건물의 개수를 출력하시오.
알고리즘 아이디어
이 코드는 GPT에 도움을 받아 작성되었습니다.
한번씩 변화를 모두 업데이트를 한다면 시간초과가 난다.
한번에 변화를 업데이트를 해야 한다.(업데이트 할 그래프가 너무 큼)
따라서 누적합으로 접근해서 풀어내야 한다.
코드
#include <string>
#include <vector>
using namespace std;
int solution(vector<vector<int>> board, vector<vector<int>> skill) {
int answer = 0;
int n = board.size();
int m = board[0].size();
vector<vector<int>> diff(n + 1, vector<int>(m + 1, 0));
for(int i = 0; i < skill.size(); i++) {
int type = skill[i][0];
int r1 = skill[i][1];
int c1 = skill[i][2];
int r2 = skill[i][3];
int c2 = skill[i][4];
int degree = skill[i][5];
if(type == 1) degree = -1 * degree;
diff[r1][c1] += degree;
diff[r1][c2 + 1] -= degree;
diff[r2 + 1][c1] -= degree;
diff[r2 + 1][c2 + 1] += degree;
}
for(int i = 0; i <= n; i++) {
for(int j = 1; j <= m; j++) {
diff[i][j] += diff[i][j - 1];
}
}
for (int j = 0; j < m + 1; j++) {
for (int i = 1; i < n + 1; i++) {
diff[i][j] += diff[i - 1][j];
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
board[i][j] += diff[i][j];
if (board[i][j] > 0) answer++;
}
}
return answer;
}
그렙에서는 유연 근무제를 실행할려고 합니다. 이때 직원들의 참여율을 높이기 위해서 일주일동안 지각을 안한 직원에게 상품을 줄려고 합니다. 이때, 희망 시각보다 10분정도는 늦어도 괜찮습니다. schedules에는 직원들의 희망 출근 시간이 저장되어있고, timelogs는 직원들의 실제 출근 데이터가 저장 되어있습니다. 주말을 제외한 주중 출근을 한번도 지각하지 않은 직원의 명수를 출력해주세요.
코딩 테스트를 풀기 위해선는 알고력과 코딩력 2가지 능력이 필요합니다. 처음에 각 능력치가 주어지고, 문제가 주어집니다. 각 문제는 푸는데 소요되는 시간, 문제를 풀기 위한 알고력 및 코딩력, 그리고 풀어낸 후 얻는 알고력 및 코딩력이 주어집니다. 만약 문제를 풀 수 없다면, 1의 시간을 소요하여 알고력 혹은 코딩력을 1 증가시킬 수 있습니다. 모든 문제를 풀기 위한 최소의 시간을 구해 출력하시오.
알고리즘 아이디어
모든 문제를 풀기 위한 최소의 알고력과 코딩력을 구한다.
이 알고력과 코딩력에 도달하기 위해 필요한 모든 경로를 DP에 저장한다. (이때 값을 비교하면서 최솟값을 저장한다.)
그 후, 최소의 알고력과 코딩력에 저장되어있는 시간을 출력한다.
초기값에서 만약 필요한 알고력과 코딩력이 최댓값을 넘었다면, 시작점을 변경한다.
코드
#include <string>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
int solution(int alp, int cop, vector<vector<int>> problems) {
int max_alp = 0, max_cop = 0;
for (auto& problem : problems) {
max_alp = max(max_alp, problem[0]);
max_cop = max(max_cop, problem[1]);
}
vector<vector<int>> dp(151, vector<int>(151, INT32_MAX));
alp = min(alp, max_alp);
cop = min(cop, max_cop);
dp[alp][cop] = 0;
for (int i = alp; i <= max_alp; i++) {
for (int j = cop; j <= max_cop; j++) {
if (i + 1 <= 150) {
dp[i + 1][j] = min(dp[i + 1][j], dp[i][j] + 1);
} if (j + 1 <= 150) {
dp[i][j + 1] = min(dp[i][j + 1], dp[i][j] + 1);
}
for (auto& problem : problems) {
int req_alp = problem[0], req_cop = problem[1];
int gain_alp = problem[2], gain_cop = problem[3], cost = problem[4];
if (i >= req_alp && j >= req_cop) {
int new_alp = min(i + gain_alp, max_alp);
int new_cop = min(j + gain_cop, max_cop);
dp[new_alp][new_cop] = min(dp[new_alp][new_cop], dp[i][j] + cost);
}
}
}
}
return dp[max_alp][max_cop];
}
플레이어 A, B가 있습니다. 각 플레이어는 시작 지점이 존재합니다.(aloc, bloc) 각 플레이어는 상하좌우 4방향으로 한칸 움직일 수 있습니다. (그러나 맵 밖으로 나갈 수 없습니다.) 한칸 움직인 순간, 자신이 있던 자리는 다시 밟을 수 없습니다. (상대 플레이어도 밟을 수 없습니다. / 경로 자체가 없어졌다고 생각해야 합니다.) 각 플레이어는 최선의 선택을 합니다.(이길 수 있으면 가장 빠르게 끝내는 방법으로 움직이고, 진다면 가장 늦게 지도록 움직입니다.) 이때, A와 B의 플레이어의 움직인 총 횟수를 출력하시오.
알고리즘 아이디어
DP로 풀었다가 너무 어려워서 GPT에 도움을 받았다...
일단 최선의 선택을 한다는 것은 모든 노드를 탐색해야 한다. (완전 탐색 진행)
가장 최선의 선택을 한다는 것은 DFS로 완전 탐색을 진행한 후에 A가 이겼는지, B가 이겼는지 판단한 후, 경우의 수를 세야 한다.
따라서 Minimax 알고리즘을 DFS에 적용시켜야 한다.
코드
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
pair<bool, int> dfs(vector<vector<int>> board, int ax, int ay, int bx, int by, bool turn) {
int x, y;
if(turn) {
x = ax; y = ay;
} else {
x = bx; y = by;
}
if (board[x][y] == 0) {
return {false, 0};
};
bool canWin = false;
int minTurn = INT32_MAX, maxTurn = 0;
board[x][y] = 0;
for (int dir = 0; dir < 4; dir++) {
int nx = x + dx[dir];
int ny = y + dy[dir];
if (nx < 0 || ny < 0 || nx >= board.size() || ny >= board[0].size()) {
continue;
} if (board[nx][ny] == 0) {
continue;
}
if (turn) {
pair<bool, int> temp = dfs(board, nx, ny, bx, by, !turn);
bool win = temp.first;
int cnt = temp.second;
if (!win) {
canWin = true;
minTurn = min(minTurn, cnt + 1);
} else {
maxTurn = max(maxTurn, cnt + 1);
}
} else {
pair<bool, int> temp = dfs(board, ax, ay, nx, ny, !turn);
bool win = temp.first;
int cnt = temp.second;
if (!win) {
canWin = true;
minTurn = min(minTurn, cnt + 1);
} else {
maxTurn = max(maxTurn, cnt + 1);
}
}
}
board[x][y] = 1;
if (canWin) {
return {canWin, minTurn};
} else {
return {canWin, maxTurn};
}
}
int solution(vector<vector<int>> board, vector<int> aloc, vector<int> bloc) {
auto [win, cnt] = dfs(board, aloc[0], aloc[1], bloc[0], bloc[1], true);
return cnt;
}
XX산은n개의 지점으로 이루어져 있습니다. 각 지점은 1부터n까지 번호가 붙어있으며, 출입구, 쉼터, 혹은 산봉우리입니다. 각 지점은 양방향 통행이 가능한 등산로로 연결되어 있으며, 서로 다른 지점을 이동할 때 이 등산로를 이용해야 합니다. 이때, 등산로별로 이동하는데 일정 시간이 소요됩니다.
등산코스는 방문할 지점 번호들을 순서대로 나열하여 표현할 수 있습니다. 예를 들어 1-2-3-2-1 으로 표현하는 등산코스는 1번지점에서 출발하여 2번, 3번, 2번, 1번 지점을 순서대로 방문한다는 뜻입니다. 등산코스를 따라 이동하는 중 쉼터 혹은 산봉우리를 방문할 때마다 휴식을 취할 수 있으며, 휴식 없이 이동해야 하는 시간 중 가장 긴 시간을 해당 등산코스의 intensity라고 부르기로 합니다.
당신은 XX산의 출입구 중 한 곳에서 출발하여 산봉우리 중 한 곳만 방문한 뒤 다시 원래의 출입구로 돌아오는 등산코스를 정하려고 합니다. 다시 말해, 등산코스에서 출입구는 처음과 끝에 한 번씩, 산봉우리는 한 번만 포함되어야 합니다. 당신은 이러한 규칙을 지키면서 intensity가 최소가 되도록 등산코스를 정하려고 합니다.
다음은 XX산의 지점과 등산로를 그림으로 표현한 예시입니다.
위 그림에서 원에 적힌 숫자는 지점의 번호를 나타내며, 1, 3번 지점에 출입구, 5번 지점에 산봉우리가 있습니다. 각 선분은 등산로를 나타내며, 각 선분에 적힌 수는 이동 시간을 나타냅니다. 예를 들어 1번 지점에서 2번 지점으로 이동할 때는 3시간이 소요됩니다.
위의 예시에서 1-2-5-4-3 과 같은 등산코스는 처음 출발한 원래의 출입구로 돌아오지 않기 때문에 잘못된 등산코스입니다. 또한 1-2-5-6-4-3-2-1 과 같은 등산코스는 코스의 처음과 끝 외에 3번 출입구를 방문하기 때문에 잘못된 등산코스입니다.
등산코스를 3-2-5-4-3 과 같이 정했을 때의 이동경로를 그림으로 나타내면 아래와 같습니다.
이때, 휴식 없이 이동해야 하는 시간 중 가장 긴 시간은 5시간입니다. 따라서 이 등산코스의 intensity는 5입니다.
등산코스를 1-2-4-5-6-4-2-1 과 같이 정했을 때의 이동경로를 그림으로 나타내면 아래와 같습니다.
이때, 휴식 없이 이동해야 하는 시간 중 가장 긴 시간은 3시간입니다. 따라서 이 등산코스의 intensity는 3이며, 이 보다 intensity가 낮은 등산코스는 없습니다.
XX산의 지점 수 n, 각 등산로의 정보를 담은 2차원 정수 배열 paths, 출입구들의 번호가 담긴 정수 배열 gates, 산봉우리들의 번호가 담긴 정수 배열 summits가 매개변수로 주어집니다. 이때, intensity가 최소가 되는 등산코스에 포함된 산봉우리 번호와 intensity의 최솟값을 차례대로 정수 배열에 담아 return 하도록 solution 함수를 완성해주세요. intensity가 최소가 되는 등산코스가 여러 개라면 그중 산봉우리의 번호가 가장 낮은 등산코스를 선택합니다.
알고리즘 아이디어
이 문제를 해결하기 위해 그래프 탐색 알고리즘을 적용해야 합니다. 일반적인 다익스트라 알고리즘을 활용하여 출입구에서 산봉우리까지 가는 최적의 경로를 찾을 수 있습니다.
왜 다익스트라를 사용해야 할까?
여러 출입구에서 출발할 수 있으므로 여러 개의 시작점을 설정해야 합니다.
가중치를 최소화하는 경로를 찾아야 하므로 최단 경로 탐색이 필요합니다.
intensity가 최소가 되는 경로를 찾아야 하므로 가중치 중 최댓값을 최소화해야 합니다.
그래프 구성: 각 지점과 연결된 등산로 정보를 인접 리스트 형태로 저장합니다.
출입구와 산봉우리 구분: 출입구와 산봉우리를 빠르게 판별할 수 있도록 별도의 배열을 사용합니다.
다익스트라 알고리즘 적용: 여러 개의 출입구에서 동시에 출발하여 산봉우리에 도착할 때까지 최소 intensity 값을 계산합니다.
최적의 산봉우리 선택: intensity가 최소인 산봉우리를 찾되, 동일한 intensity가 존재하면 번호가 작은 산봉우리를 선택합니다.
코드
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
typedef pair<int, int> Node;
vector<int> solution(int n, vector<vector<int>> paths, vector<int> gates, vector<int> summits) {
vector<vector<pair<int, int>>> mountainPath(n + 1);
vector<int> minIntensity(n + 1, INT32_MAX);
vector<bool> isGate(n + 1, false);
vector<bool> isSummit(n + 1, false);
for (auto& path : paths) {
int s = path[0], d = path[1], w = path[2];
mountainPath[s].push_back({d, w});
mountainPath[d].push_back({s, w});
}
for (int gate : gates) isGate[gate] = true;
for (int summit : summits) isSummit[summit] = true;
priority_queue<Node, vector<Node>, greater<Node>> pq;
for (int gate : gates) {
pq.push({0, gate});
minIntensity[gate] = 0;
}
int bestSummit = -1, bestIntensity = INT32_MAX;
while (!pq.empty()) {
auto [curIntensity, curNode] = pq.top();
pq.pop();
if (curIntensity > minIntensity[curNode]) continue;
if (isSummit[curNode]) {
if (curIntensity < bestIntensity || (curIntensity == bestIntensity && curNode < bestSummit)) {
bestSummit = curNode;
bestIntensity = curIntensity;
}
continue;
}
for (auto& [nextNode, weight] : mountainPath[curNode]) {
if (isGate[nextNode]) continue;
int newIntensity = max(curIntensity, weight);
if (newIntensity < minIntensity[nextNode]) {
minIntensity[nextNode] = newIntensity;
pq.push({newIntensity, nextNode});
}
}
}
return {bestSummit, bestIntensity};
}
격자의 크기를 뜻하는 정수 n, m, 출발 위치를 뜻하는 정수 x, y, 탈출 지점을 뜻하는 정수 r, c, 탈출까지 이동해야 하는 거리를 뜻하는 정수 k가 매개변수로 주어집니다. 이때, 미로를 탈출하기 위한 경로를 return 하도록 solution 함수를 완성해주세요. 단, 위 조건대로 미로를 탈출할 수 없는 경우 "impossible"을 return 해야 합니다.
알고리즘 아이디어
처음에 미로 탈출만 보고 BFS로 접근해서 풀려고 하면 시간초과가 난다.
이 문제는 Greedy로 풀어야 한다.
1. 경로가 존재하는지 판별
목표 (r, c)까지 도달하는 최소 이동 거리를 min_dist라고 하면,
int min_dist = abs(x - r) + abs(y - c);
여기서 다음 조건을 만족해야 탈출 가능성이 있습니다.
불가능한 경우 판별
이동 횟수 k가 min_dist보다 작으면 불가능
(k - min_dist) 가 짝수가 아니면 불가능
k - min_dist가 홀수면 남은 이동 횟수를 의미 없이 소모해야 하는데, 되돌아 올 수 있는 경로가 없어지므로 불가능하다.
2. 가장 빠른 사전 순으로 탐색 진행 (Greedy)
이제 (x, y)에서 (r, c)로 가는 가장 빠른 사전순 경로를 찾습니다.
'd' → 'l' → 'r' → 'u' 순서로 이동 시도
이동이 가능하면 바로 이동 (정렬 불필요)
k = 0이 되면 종료
코드
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
struct point{
int x, y, count;
string list;
};
int dy[4] = {0, -1, 1, 0};
int dx[4] = {1, 0, 0, -1};
char listup[4] = {'d', 'l', 'r', 'u'};
string solution(int n, int m, int x, int y, int r, int c, int k) {
int min_dist = abs(x - r) + abs(y - c);
if (min_dist > k || (k - min_dist) % 2 != 0) {
return "impossible";
}
string answer = "";
while (k > 0) {
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 1 || nx > n || ny < 1 || ny > m) {
continue;
}
int new_dist = abs(nx - r) + abs(ny - c);
if (new_dist <= k - 1) {
answer += listup[i];
x = nx;
y = ny;
k--;
break;
}
}
}
return answer;
}
당신은 표 편집 프로그램을 작성하고 있습니다. 표의 크기는 50 × 50으로 고정되어있고 초기에 모든 셀은 비어 있습니다. 각 셀은 문자열 값을 가질 수 있고, 다른 셀과 병합될 수 있습니다.
위에서r번째, 왼쪽에서c번째 위치를 (r,c)라고 표현할 때, 당신은 다음 명령어들에 대한 기능을 구현하려고 합니다.
"UPDATE r c value"
(r,c) 위치의 셀을 선택합니다.
선택한 셀의 값을value로 바꿉니다.
"UPDATE value1 value2"
value1을 값으로 가지고 있는 모든 셀을 선택합니다.
선택한 셀의 값을value2로 바꿉니다.
"MERGE r1 c1 r2 c2"
(r1,c1) 위치의 셀과 (r2,c2) 위치의 셀을 선택하여 병합합니다.
선택한 두 위치의 셀이 같은 셀일 경우 무시합니다.
선택한 두 셀은 서로 인접하지 않을 수도 있습니다. 이 경우 (r1,c1) 위치의 셀과 (r2,c2) 위치의 셀만 영향을 받으며, 그 사이에 위치한 셀들은 영향을 받지 않습니다.
두 셀 중 한 셀이 값을 가지고 있을 경우 병합된 셀은 그 값을 가지게 됩니다.
두 셀 모두 값을 가지고 있을 경우 병합된 셀은 (r1,c1) 위치의 셀 값을 가지게 됩니다.
이후 (r1,c1) 와 (r2,c2) 중 어느 위치를 선택하여도 병합된 셀로 접근합니다.
"UNMERGE r c"
(r,c) 위치의 셀을 선택하여 해당 셀의 모든 병합을 해제합니다.
선택한 셀이 포함하고 있던 모든 셀은 프로그램 실행 초기의 상태로 돌아갑니다.
병합을 해제하기 전 셀이 값을 가지고 있었을 경우 (r,c) 위치의 셀이 그 값을 가지게 됩니다.
"PRINT r c"
(r,c) 위치의 셀을 선택하여 셀의 값을 출력합니다.
선택한 셀이 비어있을 경우"EMPTY"를 출력합니다.
아래는 UPDATE 명령어를 실행하여 빈 셀에 값을 입력하는 예시입니다.
commands 효과
UPDATE 1 1 menu
(1,1)에"menu"입력
UPDATE 1 2 category
(1,2)에"category"입력
UPDATE 2 1 bibimbap
(2,1)에"bibimbap"입력
UPDATE 2 2 korean
(2,2)에"korean"입력
UPDATE 2 3 rice
(2,3)에"rice"입력
UPDATE 3 1 ramyeon
(3,1)에"ramyeon"입력
UPDATE 3 2 korean
(3,2)에"korean"입력
UPDATE 3 3 noodle
(3,3)에"noodle"입력
UPDATE 3 4 instant
(3,4)에"instant"입력
UPDATE 4 1 pasta
(4,1)에"pasta"입력
UPDATE 4 2 italian
(4,2)에"italian"입력
UPDATE 4 3 noodle
(4,3)에"noodle"입력
위 명령어를 실행하면 아래 그림과 같은 상태가 됩니다.
아래는 MERGE 명령어를 실행하여 셀을 병합하는 예시입니다.
commands 효과
MERGE 1 2 1 3
(1,2)와 (1,3) 병합
MERGE 1 3 1 4
(1,3)과 (1,4) 병합
위 명령어를 실행하면 아래와 같은 상태가 됩니다.
병합한 셀은 "category" 값을 가지게 되며 (1,2), (1,3), (1,4) 중 어느 위치를 선택하더라도 접근할 수 있습니다.
아래는 UPDATE 명령어를 실행하여 셀의 값을 변경하는 예시입니다.
commands 효과
UPDATE korean hansik
"korean"을"hansik"으로 변경
UPDATE 1 3 group
(1,3) 위치의 셀 값을"group"으로 변경
위 명령어를 실행하면 아래와 같은 상태가 됩니다.
아래는 UNMERGE 명령어를 실행하여 셀의 병합을 해제하는 예시입니다.
commands 효과
UNMERGE 1 4
셀 병합 해제후 원래 값은 (1,4)가 가짐
위 명령어를 실행하면 아래와 같은 상태가 됩니다.
실행할 명령어들이 담긴 1차원 문자열 배열 commands가 매개변수로 주어집니다. commands의 명령어들을 순서대로 실행하였을 때, "PRINT r c" 명령어에 대한 실행결과를 순서대로 1차원 문자열 배열에 담아 return 하도록 solution 함수를 완성해주세요.
알고리즘 아이디어
병합을 할 때, 중요한 것은 대표 셀이 정해져야 한다.
그러나, 매번 병합을 할 때마다 이 대표 셀을 찾아서 저장해야 한다.
이 기능을 Union-Find로 구현한다.
Union-Find 개념 적용
각 셀을 자신의 부모 셀을 가리키는 구조로 유지합니다.
find 함수: 현재 셀이 속한 그룹의 대표 셀을 찾습니다.
union 함수: 두 셀을 병합하여 하나의 대표 셀을 공유하게 만듭니다.
unmerge 함수: 해당 그룹의 모든 셀을 원래 상태로 되돌립니다.
각 셀의 값을 저장하는 배열을 따로 두고, 병합된 경우 대표 셀의 값을 유지합니다.
코드
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
using namespace std;
struct xy {
int x, y;
};
vector<string> split(string input, char dim) {
stringstream ss(input);
vector<string> result;
string stringbuffer;
while (getline(ss, stringbuffer, dim)) {
result.push_back(stringbuffer);
}
return result;
}
xy findParent(vector<vector<xy>>& parent, int x, int y) {
if (parent[x][y].x == x && parent[x][y].y == y) {
return {x, y};
}
return parent[x][y] = findParent(parent, parent[x][y].x, parent[x][y].y);
}
void mergeCells(int x1, int y1, int x2, int y2,
vector<vector<xy>>& parent, vector<vector<string>>& rule) {
xy root1 = findParent(parent, x1, y1);
xy root2 = findParent(parent, x2, y2);
if (root1.x == root2.x && root1.y == root2.y) return;
parent[root2.x][root2.y] = root1;
if (rule[root1.x][root1.y] == "" && rule[root2.x][root2.y] != "") {
rule[root1.x][root1.y] = rule[root2.x][root2.y];
}
}
void unmergeCells(int x, int y, vector<vector<xy>>& parent, vector<vector<string>>& rule) {
xy root = findParent(parent, x, y);
string value = rule[root.x][root.y];
vector<xy> toReset;
for (int i = 1; i <= 50; i++) {
for (int j = 1; j <= 50; j++) {
xy find = findParent(parent, i, j);
if (find.x == root.x && find.y == root.y) {
toReset.push_back({i, j});
}
}
}
for (xy c : toReset) {
parent[c.x][c.y] = {c.x, c.y};
rule[c.x][c.y] = "";
}
rule[x][y] = value;
}
vector<string> solution(vector<string> commands) {
vector<string> answer;
vector<vector<string>> rule(51, vector<string>(51, ""));
vector<vector<xy>> parent(51, vector<xy>(51));
for (int i = 1; i <= 50; i++) {
for (int j = 1; j <= 50; j++) {
parent[i][j] = {i, j};
}
}
for (string command : commands) {
vector<string> temp = split(command, ' ');
if (temp[0] == "UPDATE") {
if (temp.size() == 4) {
int x = stoi(temp[1]);
int y = stoi(temp[2]);
xy parentCell = findParent(parent, x, y);
rule[parentCell.x][parentCell.y] = temp[3];
} else {
for (int i = 1; i <= 50; i++) {
for (int j = 1; j <= 50; j++) {
if (rule[i][j] == temp[1]) {
rule[i][j] = temp[2];
}
}
}
}
}
else if (temp[0] == "MERGE") {
int x1 = stoi(temp[1]);
int y1 = stoi(temp[2]);
int x2 = stoi(temp[3]);
int y2 = stoi(temp[4]);
mergeCells(x1, y1, x2, y2, parent, rule);
}
else if (temp[0] == "UNMERGE") {
int x = stoi(temp[1]);
int y = stoi(temp[2]);
unmergeCells(x, y, parent, rule);
}
else if (temp[0] == "PRINT") {
int x = stoi(temp[1]);
int y = stoi(temp[2]);
xy parentCell = findParent(parent, x, y);
if (rule[parentCell.x][parentCell.y] == "") {
answer.push_back("EMPTY");
} else {
answer.push_back(rule[parentCell.x][parentCell.y]);
}
}
}
return answer;
}
주어진 이진트리에 더미 노드를 추가하여 포화 이진트리로 만듭니다. 루트 노드는 그대로 유지합니다.
만들어진 포화 이진트리의 노드들을 가장 왼쪽 노드부터 가장 오른쪽 노드까지, 왼쪽에 있는 순서대로 살펴봅니다.노드의 높이는 살펴보는 순서에 영향을 끼치지 않습니다.
살펴본 노드가 더미 노드라면, 문자열 뒤에 0을 추가합니다. 살펴본 노드가 더미 노드가 아니라면, 문자열 뒤에 1을 추가합니다.
문자열에 저장된 이진수를 십진수로 변환합니다.
이진트리에서 리프 노드가 아닌 노드는 자신의 왼쪽 자식이 루트인 서브트리의 노드들보다 오른쪽에 있으며, 자신의 오른쪽 자식이 루트인 서브트리의 노드들보다 왼쪽에 있다고 가정합니다.
다음은 이진트리를 수로 표현하는 예시입니다.
주어진 이진트리는 다음과 같습니다.
주어진 이진트리에 더미노드를 추가하여 포화 이진트리로 만들면 다음과 같습니다. 더미 노드는 점선으로 표시하였고, 노드 안의 수는 살펴보는 순서를 의미합니다.
노드들을 왼쪽에 있는 순서대로 살펴보며 0과 1을 생성한 문자열에 추가하면 "0111010"이 됩니다. 이 이진수를 십진수로 변환하면 58입니다.
당신은 수가 주어졌을때, 하나의 이진트리로 해당 수를 표현할 수 있는지 알고 싶습니다.
이진트리로 만들고 싶은 수를 담은 1차원 정수 배열 numbers가 주어집니다. numbers에 주어진 순서대로 하나의 이진트리로 해당 수를 표현할 수 있다면 1을, 표현할 수 없다면 0을 1차원 정수 배열에 담아 return 하도록 solution 함수를 완성해주세요.
알고리즘 아이디어
이진수 변환 함수 작성
10진수를 2진수로 변환하는 함수가 필요하다.
변환 방법: 2로 나눈 나머지를 차례로 저장하다가, 마지막에는 몫을 저장하면 된다.
이 경우, 2진수가 뒤집힌 순서로 저장되므로, 이를 트리의 좌우 대칭 형태로 해석해야 한다.
한 변의 길이가 1인 정삼각형2n+1개를 이어붙여 윗변의 길이가n, 아랫변의 길이가n+1인 사다리꼴을 만들 수 있습니다. 이때 사다리꼴의 윗변과 변을 공유하는n개의 정삼각형 중 일부의 위쪽에 같은 크기의 정삼각형을 붙여 새로운 모양을 만들었습니다. 예를 들어n이 4이고, 1번째, 2번째, 4번째 정삼각형 위에 정삼각형을 붙인 모양은 다음과 같습니다.
타일을 놓을 때 다른 타일과 겹치거나 모양을 벗어나게 놓을 수는 없습니다. 위의 예시 모양을 채우는 방법 중 일부는 다음과 같습니다.
사다리꼴의 윗변의 길이를 나타내는 정수 n과 사다리꼴 윗변에 붙인 정삼각형을 나타내는 1차원 정수 배열 tops가 매개변수로 주어집니다.
이때 문제 설명에 따라 만든 모양을 정삼각형 또는 마름모 타일로 빈 곳이 없도록 채우는 경우의 수를 10007로 나눈 나머지를 return 하도록 solution 함수를 완성해 주세요.