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

 

5639번: 이진 검색 트리

트리를 전위 순회한 결과가 주어진다. 노드에 들어있는 키의 값은 106보다 작은 양의 정수이다. 모든 값은 한 줄에 하나씩 주어지며, 노드의 수는 10,000개 이하이다. 같은 키를 가지는 노드는 없다

www.acmicpc.net

이 문제의 경우 이진 검색 트리이긴 하지만 나는 굳이 따지자면 분할 정복이라고 봐도 될거 같다. 그 이유는 이문제의 경우

pivot을 기준으로 계속 나눠가면서 트리를 분리해서 출력을 해주어야 한다. 기존에 이진트리가 자신의 인덱스/2가 부모로 배열을 사용하는 것과 달리 특이하게 들어 왔다. 일단 이문제의 풀이는 아래 사진처럼 배열을 나누어야 했다.

#include <iostream>
using namespace std;

int arr[10005];

void post(int start, int end) {
	if (start >= end) return;
	//else if (start == end-1) {
	//	cout << arr[start] << endl;
	//	return;
	//}
	int i;
	for (i = start + 1; i < end; i++)
		if (arr[start] < arr[i]) 
			break;
	post(start + 1, i);
	post(i , end);
	cout << arr[start] << endl;
	return;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int num;
	int idx=0;
	//while (true) {
	//	cin >> num;
	//	if (num == 0) {
	//		break;
	//	}
	//	else {
	//		arr[idx] = num;
	//		idx++;
	//	}
	//}
	while (cin >> num) {
		arr[idx] = num;
		idx++;
	}
	post(0, idx);
}

일단 이 문제는 입력 방식을

	while (cin >> num) {
		arr[idx] = num;
		idx++;
	}

이렇게 작성해 주어야 했는데 그이유는 이문제는 EOF를 통해 입력의 끝을 알기 때문에 우리가 프롬프트창에서 직접 사용자 입력을 해주게 되면 cin 의 기능이 끝나지 않는다 이에 나는 테스트 할때 main함수 부분의 주석을 해제해서 사용했다.

또한 이 문제의 경우 나의 post함수에 주석 부분은 성능을 올리기 위함이지만 가독성으로 볼때는 주석처리를 하는게 맞다.

그 이유는 위에 첨부한 풀이 그림을 보았을 때 원소가 2개남았을 때 무조건 start가 leaf단계이기 때문에 더이상 분할 할 필요가 없기 때문이다 하지만 맨끝에 원소가 하나 남았을 때는 굳이 출력을 해줄 필요가 없다. 이에 나는 원소가 하나 남았다는 것

if (start >= end) return;

을 이런식으로 start  인덱스와 end 인덱스가 같을 때 함수를 return 하여 더 이상 진행되지 않도록 하였다

'백준(코테준비) > 분할정복' 카테고리의 다른 글

백준 2630  (1) 2023.05.25
백준 1764  (0) 2023.02.21
백준 1074  (0) 2023.01.09

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

 

1991번: 트리 순회

첫째 줄에는 이진 트리의 노드의 개수 N(1 ≤ N ≤ 26)이 주어진다. 둘째 줄부터 N개의 줄에 걸쳐 각 노드와 그의 왼쪽 자식 노드, 오른쪽 자식 노드가 주어진다. 노드의 이름은 A부터 차례대로 알파

www.acmicpc.net

이 문제는 중위순회 전위순회 후위순회를 직접 구현해보는 문제였다 문제자체는 그리 어렵지 않았다.

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include <vector>
using namespace std;
int alpha = 65;
//26개의 원소를 0으로 초기화
struct node {
	char left;
	char right;
};
vector<node> v(26);
void preOrder(char node) {
	if (node == '.'-alpha)
		return;

	printf("%c", node + alpha);
	preOrder(v[node].left);
	preOrder(v[node].right);
}
void inOrder(char node) {
	if (node == '.'-alpha)
		return;

	inOrder(v[node].left);
	printf("%c", node + alpha);
	inOrder(v[node].right);
}
void postOrder(char node) {
	if (node == '.'-alpha)
		return;

	postOrder(v[node].left);
	postOrder(v[node].right);
	printf("%c", node + alpha);
}
int main() {
	int N;
	scanf("%d", &N);
	getchar();
	char parent, leftchild, rightchild;
	for (int i = 0; i < N; i++) {
		scanf("%c %c %c", &parent , &leftchild , &rightchild);
		getchar();
		v[parent-alpha].left = leftchild-alpha;
		v[parent-alpha].right = rightchild-alpha;
	}

	preOrder('A'-alpha);
	printf("\n");
	inOrder('A'-alpha);
	printf("\n");
	postOrder('A'-alpha);
	return 0;
}

'백준(코테준비) > 기타알고리즘' 카테고리의 다른 글

백준 1107  (0) 2023.10.08
백준 11659  (0) 2023.06.09
부채꼴 안 적 판별하기(게임 수학)  (0) 2023.06.05
중복 순열, 순열  (0) 2023.06.05

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

 

15663번: N과 M (9)

한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다. 수열은 사전 순으로 증가하는 순서로 출력해

www.acmicpc.net

이 문제는 N과 M 문제 중에 어려운 쪽에 속했다 이에 풀기 위해서는 기본적인 백트래킹 알고리즘을 사용하데 조건을 잘 맞춰주어야했다

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N, M;
int beforearr[8] = { 0, };
int arr[8];
int answer[8];
bool isused[8];
int cnt;
void solution(int level) {
	if (level == M) {
		for (int i = 0; i < M; i++) {
			cout << answer[i] << " ";
		}
		cout << endl;
		return;
	}
	int finalusing = 0;
	for (int i = 0; i < N; i++) {
		if (!isused[i] && finalusing!=arr[i] ){
			answer[level] = arr[i];
			finalusing = answer[level];
			isused[i] = true;
			solution(level + 1);
			isused[i] = false;
		}
	}

}
int main() {
	cin >> N >> M;
	for (int i = 0; i < N; i++) {
		cin >> arr[i];
	}
	sort(arr, arr + N);
	solution(0);

}

 

이 문제를 해결하는 방법이다 이 문제의 경우 백트래킹을 사용하기 위해 일단 입력받은 배열을 오름차순으로 정렬을 해주면 같은 level내에서 같은 값을 뽑아서 사용하게 되면 똑같은 수열이 나오기에 스택에서 바로 이전에 썼던 값만 안써주면 중복을 피할 수 있다 예를 들어 1 7 9 9 로 나열되어 있으면 1번째 9가 사용되면 2번째 9는 사용되지 않기 위함이다 1번째 9를 사용할때는 이전에는 7을 사용했으므로 사용할 수 있지만 2번째 9의 경우 1번째 9를 이전에 사용했으므로 사용할 수 없다 즉 바로 이전에 사용한 값을 final using이라는 변수에 넣고 이를 이용해서 앞으로 넣을 값이 중복되면 넣지 않도록 작성한다. 생각하기가 좀 까다로운 문제였던것 같다

'백준(코테준비) > 백트래킹' 카테고리의 다른 글

백준 13549  (1) 2023.06.26
백준 15686  (0) 2023.06.24
백준 1759  (0) 2023.06.04

이 문제는 dp문제이다

#include <iostream>
#include <algorithm>
using namespace std;
//dp[i][j]= 처음부터 i번째 까지의 물건을 살펴보고, 배낭의 용량이 j였을 떄 배낭에 들어간 물건의 가치합의 최댓값
//예를 들어
int dp[101][100001];
int W[101];
int V[101];
int main() {
	//N은 물건의 갯수를 의마한다.
	//K는 버틸수 있는 물건의 무게를 의미한다.
	int N, K;
	cin >> N >> K;
	for (int i = 1; i <= N; i++) {
		cin >> W[i] >> V[i];
	}


	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= K; j++) {
			if (j - W[i] >= 0) {
				//현재 무게의 최댓갑은 이전아이템까지 넣은 단계에서의 최댓값과
				//지금 아이템의 무게를 넣은 물건의 값을 비교하여 더 큰값을 넣는다.
				//i번째 물건을 넣을 지 말지가 중요하다.
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - W[i]]+V[i]);
			}
			else {
				//현재 아이템을 넣었을때 무게가 오바된다면 넣지 않고 이전걸 그대로 가져온다
				dp[i][j] = dp[i - 1][j];
			}
		}
	}
	cout << dp[N][K];
}

코드를 살펴보면 일다 우리는 가지고 있는 첫번째 아이템 부터 차근차근 가방에 넣을 것이다. 차근차근 넣을 때 제한 무게를 초과한다면 그 아이템은 넣지 않는다가 이문제의 핵심이다. 즉 i번째 아이템을 넣은 것과 안 넣은 것의 최댓값을 계속 갱신해주면서 진행하는게 해당 문제의 해결 방법이다. i=1일때 우리는 가방에 이 아이템을 넣을지 말지 결정 한다. dp[0][0]은 어차피 0이다 하지만 무게해당하는 j값이 0이기에 일단 넣지 않는다. 이에 dp[1][6]=13이다 즉 1번아이템을 넣었을 때의 무게는 6이고 13이다라는 의미이다 이제 2번아이템을 넣는다고 가정해보자 2번아이템도 마찬가지로 진행이된다. dp[4][4]의 가치는 일단 8이다 하지만 이제 dp[6]으로 간다면 2번까지 넣어서 6이하의 무게를 만든 가방보다 1번만 넣어서 6이하의 무게를 가진 가방의 가치가 더높으므로 dp[2][6]=13이다. 

자이제 3번아이템까지 넣는다고 가정하자  일단 dp[3][3]=6이다 dp[2][4]=8이고 이에 따라 dp[3][4]=8이다

dp[3][7]의 기준으로 보자 지금 까지는 dp[1][6]의 값이 계속 들어 와서 13이었을 것이다. 하지만 3번 아이템을 넣는다고 가정해보았을 때 dp[2][4]+dp[3][3] 즉 dp[2][4]+V[i]의 값이 기존의 dp[2][7]즉 dp[1][6]의 값이 계속 넣어진 상황 보다 큼으로

갱신된다 

'백준(코테준비) > DP' 카테고리의 다른 글

백준 1916  (0) 2023.06.28
백준 1753  (0) 2023.06.28
백준 9095  (0) 2023.05.25
백준 2293  (0) 2023.01.09
백준 12865  (0) 2023.01.08

이 문제의 경우 내가 본 코테에서 나온 문제를 임의로 각색한 문제이다. 충분히 풀 수 있는 문제였으나 배가 고파서 못풀었지만 생각하니까 매우 쉬운 문제였다.. 이래서 아침밥이 중요한가 보다.

#include <iostream>
#include <stack>
#include <vector>
using namespace std;
int arr[1001][1001];
bool visited[1001][1001];
int main() {

	int N;
	cin >> N;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cin >> arr[i][j];
		}
	}
	int hp=100;
	int maxhp = 100;
	int startX, startY;
	stack<pair<int, int>> bfss;
	cin >> startX >> startY;
	bfss.push(make_pair(startX, startY));

	while (!bfss.empty()) {
		startX = bfss.top().first;
		startY = bfss.top().second;
		visited[startX][startY] = true;
		if (arr[startX][startY] == 1) {

		}
		else if (arr[startX][startY == 2]) {
			hp -= 20;
			if (hp <= 0) {
				break;
			}

		}
		else if (arr[startX][startY] == 3) {
			hp += 30;
			arr[startX][startY] = 1;
		}

		if (startX + 1 < N && !visited[startX + 1][startY]&&arr[startX+1][startY]!=0) {
			bfss.push(make_pair(startX + 1, startY));
		}
		else if (startX - 1 >= 0 && !visited[startX - 1][startY]&& arr[startX - 1][startY]!=0) {
			bfss.push(make_pair(startX - 1, startY));
		}
		else if (startY - 1 >= 0 && !visited[startX][startY - 1]&& arr[startX][startY - 1]!=0) {
			bfss.push(make_pair(startX, startY - 1));
		}
		else if (startY + 1 < N && !visited[startX][startY + 1]&& arr[startX][startY + 1]!=0) {
			bfss.push(make_pair(startX, startY + 1));
		}
		else {
			bfss.pop();
		}
	}
	cout << hp;
}

문제: 플레이어는 N x N 던전 안에 있다 이때 플레이어는 자신이 갈 수 있는 모든 곳을 탐험 해야 한다. 이 던전에는 몬스터방 물약방 일반방이 있으며 몬스터방에 들어갔을 시 몬스터는 잡지 못하고 플레이어의 피가 20 감소한다 물약방에 들어가면 그 방은 일반 방으로 바뀌고 플레이어의 피가 30이 증가한다. 플레이어가 던전을 모두 돌고 나서의 플레이어의 HP를 출력하라. 플레이어의 HP가 0일시 즉시 탐험을 종료하고 0을 출력한다.

출력 예시:

3
1 3 1
0 2 0
0 2 0
0 0

정답:40

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

 

11659번: 구간 합 구하기 4

첫째 줄에 수의 개수 N과 합을 구해야 하는 횟수 M이 주어진다. 둘째 줄에는 N개의 수가 주어진다. 수는 1,000보다 작거나 같은 자연수이다. 셋째 줄부터 M개의 줄에는 합을 구해야 하는 구간 i와 j

www.acmicpc.net

이 문제는 재시도를 엄청 했다 첫번째 풀이로는 평범하게 사용하는 누적합을 사용해서 풀어보았다. 실버3이라서 확실히 이런 기초적인 코딩을 쓰지는 않았을 거 같지만 일단 해보았다. 당연히 시간초과가 발생했다. 그럼 무슨 알고리즘을 써야할까 알아보다 슬라이딩 윈도우 알고리즘이라는 기억 어딘가에 쳐박아놓은 알고리즘이 생각 났다. 이에 iostream의 cin과 cout을 stdio와 sync까지 끊고 코드를 작성하였음에도 시간초과가 발생했다. 이에 3번째에서는 iostream을 stdio.h 로 바꾸고 실행하니까 정상 적으로 실행 되었다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
using namespace std;
int N;
int M;
int arr[100001] = { 0, };
int i, j;
int main() {

	int temp1, temp2;
	scanf("%d %d", &N, &M);
	for (int i = 1; i <= N; i++) {
		scanf("%d", &arr[i]);
		arr[i] = arr[i] + arr[i - 1];
	}
	for (int i = 0; i < M; i++) {
		scanf("%d %d", &temp1, &temp2);
		printf("%d\n", arr[temp2] - arr[temp1 - 1]);
	}
}

이런 식으로 배열에 누적값을 저장해 줌으로서 범위를 구할 때 2 5를 입력했을 때를 예시로들면 5까지 입력한 값에서 1까지 누적된값을 빼면 2에서5의 누적값이 나온다 기존에 누적시키는 것보다 O(1)의 시간밖에 걸리지 않아 시간초과 가 발생하지 않는다.

'백준(코테준비) > 기타알고리즘' 카테고리의 다른 글

백준 1107  (0) 2023.10.08
백준 1991  (0) 2023.06.19
부채꼴 안 적 판별하기(게임 수학)  (0) 2023.06.05
중복 순열, 순열  (0) 2023.06.05

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

 

14940번: 쉬운 최단거리

지도의 크기 n과 m이 주어진다. n은 세로의 크기, m은 가로의 크기다.(2 ≤ n ≤ 1000, 2 ≤ m ≤ 1000) 다음 n개의 줄에 m개의 숫자가 주어진다. 0은 갈 수 없는 땅이고 1은 갈 수 있는 땅, 2는 목표지점이

www.acmicpc.net

이 문제는 전형적인 bfs문제이다 일단 예시로 주어지는 그림부터가 이문제는 bfs로 푸는 것이다라고 알려주고 있다. 이에 이문제는 bfs로 풀어주면 된다 bfs 문제는 queue를 많이 사용한다.

#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int N, M;
int arr[1002][1002] = { 0,};
int answer[1002][1002] = {0,};
int startX, startY;
queue <pair<int,int>> bfsq;
int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	cin >> N >> M;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			int temp;
			cin >> temp;
			arr[i][j] = temp;
			if (temp == 2) {
				startX = i;
				startY = j;
			}
		}
	}
	bfsq.push(make_pair(startX, startY));
	answer[startX][startY] = 0;
	while (!bfsq.empty()) {
		startX = bfsq.front().first;
		startY = bfsq.front().second;
		bfsq.pop();
		if (arr[startX][startY + 1] == 1 && answer[startX][startY + 1] == 0) {
			bfsq.push(make_pair(startX, startY + 1));
			answer[startX][ startY + 1] = 1 + answer[startX][startY];
		}
		if (arr[startX][startY-1] == 1 && answer[startX][startY - 1] == 0) {
			bfsq.push(make_pair(startX, startY - 1));
			answer[startX][startY - 1] = 1 + answer[startX][startY];
		}
		if (arr[startX+1][startY] == 1 && answer[startX+1][startY] == 0) {
			bfsq.push(make_pair(startX+1, startY));
			answer[startX+1][startY] = 1 + answer[startX][startY];
		}
		if (arr[startX-1][startY ] == 1 && answer[startX-1][startY] == 0) {
			bfsq.push(make_pair(startX-1, startY));
			answer[startX-1][startY] = 1 + answer[startX][startY];
		}
	}

	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			if (answer[i][j] == 0&& arr[i][j] == 1) {
				cout << -1 << " ";
			}
			else {
				cout << answer[i][j] << " ";
			}
		}
		cout << endl;
	}
}

 

전체 코드는 이렇게 되고 하나하나 설명을 하도록 하겠다.

bfsq.push(make_pair(startX, startY));
	answer[startX][startY] = 0;
	while (!bfsq.empty()) {
		startX = bfsq.front().first;
		startY = bfsq.front().second;
		bfsq.pop();
		if (arr[startX][startY + 1] == 1 && answer[startX][startY + 1] == 0) {
			bfsq.push(make_pair(startX, startY + 1));
			answer[startX][ startY + 1] = 1 + answer[startX][startY];
		}
		if (arr[startX][startY-1] == 1 && answer[startX][startY - 1] == 0) {
			bfsq.push(make_pair(startX, startY - 1));
			answer[startX][startY - 1] = 1 + answer[startX][startY];
		}
		if (arr[startX+1][startY] == 1 && answer[startX+1][startY] == 0) {
			bfsq.push(make_pair(startX+1, startY));
			answer[startX+1][startY] = 1 + answer[startX][startY];
		}
		if (arr[startX-1][startY ] == 1 && answer[startX-1][startY] == 0) {
			bfsq.push(make_pair(startX-1, startY));
			answer[startX-1][startY] = 1 + answer[startX][startY];
		}
	}

일단 위 코드의 이부분은 pair로 이루어진 큐에서 값을 뽑고 그값을 기준으로 상하좌우의 값을 큐에다가 다시 넣어준다 그후 넣어준큐의 순서에대한 값이 저장되어있는 answer배열에 나의 방문번째수 +1을 넣어서 해준다 즉 내가 2번 layer에 자식이라면 나의 상하좌우는 3번 layer 에 자식이된다

트리로 그리게 되면 이런 구조가 된다. 그후 내가 몇번째 layer에 있는지를 answer배열에 저장해주면 된다.

'백준(코테준비) > DFS,BFS' 카테고리의 다른 글

백준 16928  (0) 2023.10.21
백준 1389  (1) 2023.10.09
백준 11724  (0) 2023.06.01
백준 2667  (0) 2023.01.02
백준 1012  (0) 2022.12.29

최근에 본 코테에서 나온 문제인데 프로그래머스에서 알고리즘 문제를 출제하는 기업들의 단골 기출 문제인 듯 하다 실제로 다른 회사에서도 출제된 사례가 있었다.같이 제공되는 이미지도 많이 겹치는 것 같다.

내적의 개념과 응용을 코테에 녹인 문제 인거 같다. 기억이 잘 안나고 그림도 기억나는데로 그려서 올리겠다

문제 :

한 게임의 캐릭터가 스킬을 사용한다.

해당 캐릭터가 스킬 사용시 스킬의 범위는 부채꼴이다.

해당 부채꼴 범위 안에 적이 있다면, 적은 데미지를 받지만, 범위 밖이라면 데미지를 받지 않는다.

데미지를 받는 적의 수를 Return하세요.

 

조건1 : 스킬을 사용하는 주체인 게임 캐릭터는 항상 0,0 위치에 있다.

조건2 : 적들은 0,0에 있을 수 없으며, 겹쳐있지 않다.

조건3 : 캐릭터와 일직선상에 적이 2명 이상 겹쳐있어도, 범위 안에만 들어오면 데미지를 받는 것으로 인식한다.

 

주어지는 값 : 

1. 스킬을 사용하기위해 위치해있는 마우스 좌표 int x,y

2. 스킬의 길이(반지름) int r

3. 각도 int d

4. 적들의 위치 xn, yn이 담긴 int형 2중벡터 vector<vector<int> > target

============================================================================================

이문제의 경우 나는 단계를 2개로 나눠서 풀 것이다. 1번 해당 적이 나를 기준으로 스킬범위 안에 있는가를 먼저 검증한다.

자 이 공식을 사용하면 된다. 어차피 우리는 좌표가 0,0이기 떄문에 실제로 해당 적의 x좌표의 제곱과 y좌표의 제곱을 더한것에 제곱근이 입력된 스킬의 길이보다 작으면 된다. 

 

또한 게임수학에서 내적은 두 벡터의 각도를 알려준다 이를 이용해 위에서 걸러낸 애들을 2차로 걸러준다. 이 때 우리가 사용할 함수는 acos()이다 이 함수의 경우 안에 내적으로 나온값을 넣어주면 우리가 원하는 각도의 값이 나온다 이를이용해 구현해보도록 하겠다.

자 여기서 빨간 부분을 좌변으로 이항 시켜 보다 그럼 내적을 구하면 벡터의 크기의 곱으로 내적을 나무녀 cos인 값이 나오고 이를 acos에 넣으면 각도인 세타값이 나온다.

#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
double Distance(double x, double y) {
	double distance;
	distance = sqrt(pow(x, 2) + pow(y, 2));
	return distance;
}

double  DotProduct(double x1, double y1, double x2, double y2) {
	return (x1 * x2) + (y1 * y2);
}

double sizeOfVector(double x, double y) {
	double size;
	size= sqrt(pow(x, 2) + pow(y, 2));
	return size;
}
int solution(int x, int y, int r, double d, vector<vector<int>>target) {
	int cnt = 0;
	for (int i = 0; i < target.size(); i++) {
		if (Distance(target[i][0], target[i][1])<=r) {
			if (acos(DotProduct(x, y, target[i][0], target[i][1]) / (sizeOfVector(x, y) * sizeOfVector(target[i][0], target[i][1])))<=d) {
				cnt += 1;
			}
		}
	}
	return cnt;
}
int main() {
	vector<vector<int>> target = { {1,3},{1,1},{4,3},{9,9},{-2,8} };
	cout<<solution(2, 4, 3, 60, target);
}

이를 코드로 작성하면 이렇게 된다.

'백준(코테준비) > 기타알고리즘' 카테고리의 다른 글

백준 1107  (0) 2023.10.08
백준 1991  (0) 2023.06.19
백준 11659  (0) 2023.06.09
중복 순열, 순열  (0) 2023.06.05

+ Recent posts