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

이번에 모회사 코테를 보는 데 내가 못풀었던 문제에서 중복순열을 2번사용하여 경우의 수를 구하는 브루트포스 방식의 문제가 출제 되었던 거 같다. 내가 생각한게 정답이 아닐 수 도 있지만 적어도 내가 생각한데로 풀기 위해서는 중복순열과 순열을 구현했어야 했다. 하지만 오랫동안 기본적인 알고리즘 조차 손을 놓았어서. 역시 급하게 준비한 코테답게 불합격 메일을 기다리고 있다. 확실히 불합격이 되더라도 코테를 직접 보면서 어떤 식으로 공부해야할지 감이 잡히기 시작했다.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//중복 순열
int caseNum;
int arr[100000];
bool vectorIndexUsed[100000];
void DuplicatePermutation(int level, vector<int> caseVector) {
	if (level == caseNum) {
		for (int i = 0; i < caseNum; i++) {
			cout << arr[i];
		}
		cout << endl;
		return;
	}
	for (int i = 0; i < caseVector.size(); i++) {
		arr[level] = caseVector[i];
		DuplicatePermutation(level + 1, caseVector);
	}
}


void Permutation(int level, vector<int> caseVector) {
	if (level == caseNum) {
		for (int i = 0; i < caseNum; i++) {
			cout << arr[i];
		}
		cout << endl;
		return;
	}
	for (int i = 0; i < caseVector.size(); i++) {
		if (!vectorIndexUsed[i]) {
			vectorIndexUsed[i] = true;
			arr[level] = caseVector[i];
			Permutation(level + 1, caseVector);
			vectorIndexUsed[i] = false;
		}
	}
}

void Combination(int level, vector<int> caseVector, int beforeIndex) {
	if (level == caseNum) {
		for (int i = 0; i < caseNum; i++) {
			cout << arr[i];
		}
		cout << endl;
		return;
	}
	for (int i = beforeIndex; i < caseVector.size(); i++) {
		arr[level] = caseVector[i];
		Combination(level + 1, caseVector, beforeIndex + 1);
	}
}

int main() {
	cin >> caseNum;
	vector<int> dupPermuTest = { 1,4,5,2 };
	DuplicatePermutation(0, dupPermuTest);
	cout << "====================================="<<endl;
	Permutation(0, dupPermuTest);
	cout << "====================================="<<endl;
	sort(dupPermuTest.begin(), dupPermuTest.end());
	Combination(0, dupPermuTest, 0);
}

일단 기억나는 것은 주어진 벡터에서 몇명을 뽑아야하는 것이었다 이에 나는 중복순열,순열,조합순으로 현재 구현했다.

void DuplicatePermutation(int level, vector<int> caseVector) {
	if (level == caseNum) {
		for (int i = 0; i < caseNum; i++) {
			cout << arr[i];
		}
		cout << endl;
		return;
	}
	for (int i = 0; i < caseVector.size(); i++) {
		arr[level] = caseVector[i];
		DuplicatePermutation(level + 1, caseVector);
	}
}

중복 순열의 경우 똑같은 걸 여러번 사용해도 되니 굳이 사용했는지 안했는 지 체크할 필요가 없다

void Permutation(int level, vector<int> caseVector) {
	if (level == caseNum) {
		for (int i = 0; i < caseNum; i++) {
			cout << arr[i];
		}
		cout << endl;
		return;
	}
	for (int i = 0; i < caseVector.size(); i++) {
		if (!vectorIndexUsed[i]) {
			vectorIndexUsed[i] = true;
			arr[level] = caseVector[i];
			Permutation(level + 1, caseVector);
			vectorIndexUsed[i] = false;
		}
	}
}

순열의 경우 vector에서 순서가 다르면 다른것으로 인정하고 중복은 허하지 않는다

void Permutation(int level, vector<int> caseVector) {
	if (level == caseNum) {
		for (int i = 0; i < caseNum; i++) {
			cout << arr[i];
		}
		cout << endl;
		return;
	}
	for (int i = 0; i < caseVector.size(); i++) {
		if (!vectorIndexUsed[i]) {
			vectorIndexUsed[i] = true;
			arr[level] = caseVector[i];
			Permutation(level + 1, caseVector);
			vectorIndexUsed[i] = false;
		}
	}
}

조합은 중복을 허하지도 않고 순서가 달라도 같은 수를 뽑았으면  허용치 않는다.

void duplicateCombination(int level, vector<int> caseVector, int beforeIndex) {
	if (level == caseNum) {
		for (int i = 0; i < caseNum; i++) {
			cout << arr[i];
		}
		cout << endl;
		return;
	}
	for (int i = beforeIndex; i < caseVector.size(); i++) {
		arr[level] = caseVector[i];
		duplicateCombination(level + 1, caseVector, i);
	}
}

중복 조합은 같은 수를 뽑을 수 있고 순서가 존재한다 이에 같은수는 뽑을 수 있지만 순서가 다르고 동일한 요소로 이루어져있는 것은 이전에 뽑은것과 같음으로 허용치 않는다

 

이 정도 문법은 꼭 기억하도록 하자

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

백준 1107  (0) 2023.10.08
백준 1991  (0) 2023.06.19
백준 11659  (0) 2023.06.09
부채꼴 안 적 판별하기(게임 수학)  (0) 2023.06.05

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

 

1759번: 암호 만들기

첫째 줄에 두 정수 L, C가 주어진다. (3 ≤ L ≤ C ≤ 15) 다음 줄에는 C개의 문자들이 공백으로 구분되어 주어진다. 주어지는 문자들은 알파벳 소문자이며, 중복되는 것은 없다.

www.acmicpc.net

이 문제는 일단 백준상에서 골드 5로 되어있는 문제다 근데 이문제를 보았을 때 느낀게 과연 내가 이 문제가  백트래킹인걸 모르고 풀었을 때 빠르게 정답을 유추 할 수 있었을까? 절대 아니다. 요즘 해당 알고리즘이 주어질 경우에는 그 알고리즘으로 문제를 빠르게 풀지만 내가 어떤 문젠지를 모르면 풀 수 있을 지는 모르겠다. 확실히 실무를 보다보니 머릿속에 생각한 것을 그대로 구현하는 구현능력은 조금 올라갔는데 앞으로도 계속 좋은 일이 있었으면 좋겠

#include <iostream>
#include <algorithm>
using namespace std;
int N, M;
char arr[16];
char answer[16];
int cnta;
int cntj;
bool isPassword;
int solution(int level, int beforeindex) {
	if (level == N) {
		cnta = 0;
		cntj = 0;
		isPassword = false;
		for (int i = 0; i < N; i++) {
			if (answer[i] == 'a' || answer[i] == 'e' || answer[i] == 'i' || answer[i] == 'o' || answer[i] == 'u')
			{
				cnta++;
			}
			else
				cntj++;
			if (cnta > 0 && cntj > 1) {
				isPassword = true;
				break;
			}
		}
		if (isPassword) {
			for (int i = 0; i < N; i++) {
				cout << answer[i];
			}
			cout << endl;
		}
	}
	else {
		for (int i = beforeindex + 1; i <= M; i++) {
			answer[level] = arr[i];
			solution(level + 1, i);
		}
	}
	return 0;

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

}

이코드의 경우 모음의 개수를 세주는 CNTA 자음의 개수를 세주는 CNTJ라는 변수가 존재 한다 이 변수의 경우 루프를 돌다가 특정 조건을 만족했을 때 바로 루프를 탈출하게 해준다. 즉 최종 4글자 가 모였을 때 이 문자열이 모음이 1개이상 자음이 2개이상이면 더이상 조건을 판단할 필요없으니 루프를 탈출하게 해주는 것이다.

	else {
		for (int i = beforeindex + 1; i <= M; i++) {
			answer[level] = arr[i];
			solution(level + 1, i);
		}
	}

 

이 부분의 경우는 재귀를 이용해서 백트래킹을 하기 위함인데 정렬되어있는 arr값에서 자기 이전의 index보다 큰 인덱스 부터 시작하기에 무조건 오름차순이 된다.

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

백준 13549  (1) 2023.06.26
백준 15686  (0) 2023.06.24
백준 15663  (1) 2023.06.15

+ Recent posts