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

 

1697번: 숨바꼭질

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

프로그래머스 문제를 풀고 이문제를 푸니 너무 쉽게 느껴졌다 알고리즘 수련이 아주 부족하다고 느껴졌다 더 열심히 해서 제발 취업을 애햐하는데 이문제의 경우는 문제의 답으로 최소경로수를 원하는 것이기 때문에 최소 경우의 수를 확정적으로 반환해주는 BFS를 사용해주어야 한다 이문제 자체는 실버 1이지만 문제도 짧고 해서 이해하기가 매우 편했다. 이 문제의 경우 bfs를 총 3가지 경우로 짜주면 그냥 해결되는 문제열다 X-1 ,X+1 ,2*X 자기 자신에대해서 자식이 이렇게 

만들어지기 떄문에 bfs의 범위를 이렇게 3개씩 넓혀주면 빠르게 끝난다. 

BFS의 특징으로는 큐를 사용하면 매우 편해진다는 장점이 있다 이문제의 경우도 마찬가지다 큐를 사용해서 자기를 없애면서 자기자식은 큐에 넣게되면 BFS가 된다 이전 문제에서도 큐를 이용해서 풀었기 때문에 이번문제도 큐를 이요했지만 이번에는 visited 배열에 자기가 몇대손인지를 넣을 수 있게 코드를 짜보았다

#include <iostream>
#include <queue>
using namespace std;
int visited[200002];
int N, K;

int main() {
	cin >> N >> K;
	queue<int> hs;
	hs.push(N);
	visited[N] = 0;
	while (true) {
		if (hs.front() == K) {
			break;
		}
		if (hs.front() > 0) {
			if (!visited[hs.front() - 1]) {
				hs.push(hs.front() - 1);
				visited[hs.front() - 1] = visited[hs.front()] + 1;
			}
		}
		if (hs.front() < 100000) {
			if (!visited[hs.front() + 1]) {
				hs.push(hs.front() + 1);
				visited[hs.front() + 1] = visited[hs.front()] + 1;
			}
		}
		if (hs.front() <= 50000) {
			if (!visited[hs.front() * 2]) {
				hs.push(hs.front() * 2);
				visited[hs.front() * 2] = visited[hs.front()] + 1;
			}
		}
		hs.pop();
	}
	cout << visited[K];
}

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

백준 2667  (0) 2023.01.02
백준 1012  (0) 2022.12.29
백준 24480  (1) 2022.12.21
백준 24479  (0) 2022.12.20
백준 2178  (0) 2022.12.18

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

 

24479번: 알고리즘 수업 - 깊이 우선 탐색 1

첫째 줄에 정점의 수 N (5 ≤ N ≤ 100,000), 간선의 수 M (1 ≤ M ≤ 200,000), 시작 정점 R (1 ≤ R ≤ N)이 주어진다. 다음 M개 줄에 간선 정보 u v가 주어지며 정점 u와 정점 v의 가중치 1인 양

www.acmicpc.net

이 문제의 경우 쉽다  dfs 는 자기 자식으로 쭉내려가기 때문에 일단 자기 자식들중 방문하지 않은 자식있으면 재귀로 쭉쭉내려간다 갈 수 없는곳을 만나면 자기 부모로 돌아가 갈 수 있는 곳을 다시 탐색하는걸 반복한다 그렇기 때문에 일단 재귀로 콜한다음 자기자식이 방문했는지 아닌지 검사하고 방문했으면 conitnue 문을 통해 방문을 건너뛴다 재귀기 때문에 갈곳이 없어 리턴되면 자기자신의 부모가 갈곳을 탐색한다 

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> vertex[200001];
int visitednum[100001];
bool visited[100001] = { false, };
int countnum = 0;
void dfs(int start) {
	countnum += 1;
	visitednum[start] = countnum;
	visited[start] = 1;
	for (int i = 0; i < vertex[start].size(); i++) {
		if (visited[vertex[start][i]] == true) {
			continue;
		}
		dfs(vertex[start][i]);
	}
}
int main() {
	int vertexnum, edgenum, startvertex;
	cin >> vertexnum >> edgenum >> startvertex;
	for (int i = 1; i <= edgenum; i++) {
		int temp1 = 0;
		int temp2 = 0;
		cin >> temp1 >> temp2;
		vertex[temp1].push_back(temp2);
		vertex[temp2].push_back(temp1);
	}
	for (int i = 1; i <= vertexnum; i++) {
		sort(vertex[i].begin(), vertex[i].end());
	}
	dfs(startvertex);
	for (int i = 1; i <= vertexnum; i++) {
		cout << visitednum[i]<<'\n';
	}

}

일단 위에 코드를 보게되면  visitednum이라는 것이 존재 한다 visitednum은 i번째가 루트로부터 몇번째에 갈 수 있는지를 visitednum[i] 에 저장 해준다 이것을 이용해 후에 답을 출력할 것이다. 개인적으로 배열을 써야하는 알고리즘 문제들은 visualstudio에서 stack 사이즈 문제로 오류를 엄청 띄우기 때문에 거의 전역으로 설정 해주는게 좋다. 뭐 다음 코드는 이전글에 있는 DFS BFS 알고리즘 문제에 있는 방식과 똑같다 나랑연결되 있는애들을 나의 vertex에 넣어 준다. 

예시로 백준에 input값을 보자

5 5 1
1 4
1 2
2 3
2 4
3 4

이런식으로 입력을 받아오면

vertex[1]에는 4,2

vertex[2]에는 1,3,4

vertex[3]에는 2,4

vertex[4]에는 1,2,3

이 들어가게 된다 DFS에서의 간선은 양방향으로 갈수 있기때문에 양쪽에 값을 넣어 준 것 이다. 그 이후에  이 vector를 오름차 순으로 정렬해주고 나와 연결된애에게로 간다 지금 상황에선 2부터 쭉가서 끝까지 간다 쭉가다가 더 이상 갈 수 없으면 재귀함수는 return으로 자기 caller에게 돌아가기 때문에 자기 부모로 돌아가게된다 그후 부모도 다른 곳으로 갈 수 있는 지 없는지 판단하고 자기자신의 부모로 간다 이렇게 반복되어  DFS가 완성된다

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

백준 1012  (0) 2022.12.29
백준 1697  (0) 2022.12.27
백준 24480  (1) 2022.12.21
백준 2178  (0) 2022.12.18
백준 1260  (1) 2022.12.17

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

 

2156번: 포도주 시식

효주는 포도주 시식회에 갔다. 그 곳에 갔더니, 테이블 위에 다양한 포도주가 들어있는 포도주 잔이 일렬로 놓여 있었다. 효주는 포도주 시식을 하려고 하는데, 여기에는 다음과 같은 두 가지 규

www.acmicpc.net

dp문제는 풀 때 마다 점화식이 중요하다고 생각되어진다 역시 이번 문제도 점화식인데

이번문제의 경우 기존에 올렸던과는 다르게 3개의 후보중 하나를 뽑는 방식으로 생각해주어야 한다

그이유는 이번 문제에서 핵심적인 내용이 연속으로 3개의 포도주를 못마신다는 거였으니  그거를 이용해서 풀어야 한다

1.O O X O

2.O X O O

3.X O O X

이문제는 위에처럼 3가지 경우의 수가 존재 한다 즉 N번째 와인이 존재한다고 가정했을때 N번째 와인을 마신다고 가정했을때 첫번째로 마시냐 두번째로 마시냐 혹은 안마시냐 이렇게 3개의 경우의 수가 존대 한다. 이를 점화식으로 나타내면

1은 dp[j-2]+arr[j];

2는 dp[j-3]+arr[j-1]+arr[j]

3은 dp[j-1]

이다 1은 j번째 포도주를 먹기로 가정했기 때문에 내이전은 못마시고 나보다 2개전에 있는 애를 마실 수 있다

2는 나도 마시고 내이전도 마신다고 가정한것이다 

마지막은 나를 안마셨기 때문에 나의 이전까지의 최대값만 필요하다 어차피 이렇게 우리가 3개의 식으로 나눴을 경우 3잔을 연속으로 마시는 경우의 수는 발생하지 않는다

#include <iostream>
#include <algorithm>
using namespace std;
int dp[10001];
int arr[10001];
int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> arr[i];
	}
	dp[1] = arr[1];
	dp[2] = arr[1] + arr[2];

	for (int j = 3; j <= n + 1; j++) {
		dp[j] = dp[j - 1];
		dp[j] = max(dp[j], dp[j - 2] + arr[j]);
		dp[j] = max(dp[j], dp[j - 3] + arr[j - 1] + arr[j]);

	}
	cout << dp[n] << endl;
}

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

백준 11052  (0) 2022.12.26
백준 10844  (0) 2022.12.19
백준 1912  (0) 2022.12.19
백준 1932  (1) 2022.12.16
백준 11053  (0) 2022.12.15

+ Recent posts