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

 

9465번: 스티커

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 n (1 ≤ n ≤ 100,000)이 주어진다. 다음 두 줄에는 n개의 정수가 주어지며, 각 정수는 그 위치에 해당하는 스티커의

www.acmicpc.net

이문제의 거의 다풀어놓고 위에 배열크기를 잘못 설정해서 계속 틀렸다. 진짜 알고리즘 문제 풀면서 항상 느끼는 거지만 배열의 크기에서 오타나면 항상 틀리는 거같다 이문제의 경우 총 2가지의 케이스를 생각해줄 수 있다

자 40을 예시로 들면 자기이전에 변을 맞대지 않는애들 고르면 자동적으로  2번째거 이전 위에거가 선택 된다

2번째거 이전에 반대쪽애를 선택해주면 3번째거 이전에 위에거 가 선택 된다 이렇게 짠이유는 이전꺼 아래거와 2번째전거 위에거 더한게 2번째거 전에 거와 3번째전에거의 위에거의 합이 더 클 수 있기 때문이다 이에 이 문제의 점화식은

dp[l][0]=max(dp[l - 1][1] + card[l][0], dp[l - 2][1] + card[l][0])

이렇게 맨마지막에 위에거를 선택했을 때와

 

dp[l][1]=max(dp[l - 1][0] + card[l][1], dp[l - 2][0] + card[l][1])

이렇게 맨마지막에 아래거를 선택 했을 때 2개가 존재한다

 

#include <iostream>
#include <algorithm>
int dp[100001][2];
int card[100001][2];
using namespace std;
int main() {
	int T;//테스트케이스
	int n;//해당하는 스티커의 점수
	cin >> T;
	for (int i = 0; i < T; i++) {
		cin >> n;
		for (int j = 0; j < 2; j++) {
			for (int k = 1; k <= n; k++) {
				cin >> card[k][j];
			}
		}
               
		dp[1][0] = card[1][0];
		dp[1][1] = card[1][1];
		for (int l = 2; l <= n; l++) {
			dp[l][0] = max(dp[l - 1][1] + card[l][0], dp[l - 2][1] + card[l][0]);
			dp[l][1] = max(dp[l - 1][0] + card[l][1], dp[l - 2][0] + card[l][1]);
		}
		cout << max(dp[n][0], dp[n][1])<<'\n';
	}
}

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

백준 2293  (0) 2023.01.09
백준 12865  (0) 2023.01.08
백준 11052  (0) 2022.12.26
백준 10844  (0) 2022.12.19
백준 2156  (0) 2022.12.19

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://school.programmers.co.kr/learn/courses/30/lessons/17684

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

백준만 풀다가 프로그래머스 문제가 빡세다고 해서 풀어보았다 개어렵다 kakao의 문제는 문자열 위주로 코딩테스트?가 진행 되는건가 싶었는데 오늘 풀고 나서 kakao의 문제는 대부분 문자열 처리인 거 같다는 생각을 했다 오늘 진행한건 일단 lv2  였는데 저녁을 안먹어서 그런지 오지게 안풀렸다 일단 이문제를 푸는데 약 1시간 반정도 걸렸으니 실제로 이문제가 나왔으면 코테에서 널어졌을 거 같다. 나는 일단 이문제를 이렇게 생각했다 사전에서 일단 1개의 문자가 맞는지 탐색한다 맞으면 자신과 자신의 다음문자를 합쳐서 나 이후로 검사한다 만약 또나온다면 합친 문자열에 또 그 다음문자를 합쳐서 검색한다. 그 후 반복이 끝나면 합치기 전에 나의 index를 저장 한다. 이 index는 즉 문자들을 합쳤을때 최종적으로 벡터에 존재하는 문자열을 의미한다.

#include<iostream>
#include<vector>
#include<string>
using namespace std;
vector<int> solution(string msg) {
    vector<int> answer;
    char start = 'A';
    int k = 0;
    vector<string> dictionary;
    for (int i = 1; i <= 26; i++) {
        dictionary.push_back(string(1, start));
        start++;
    }


    for (int i = 0; i < msg.length(); i++) {
        string temp = string(1,msg[i]);
        int endnumber=0;
        for (int j = 0; j < dictionary.size(); j++) {
            if (temp == dictionary[j]) {
                temp = temp + msg[i += 1];
                endnumber = j+1;
            }
        }
        answer.push_back(endnumber);
        if ((i) == msg.length()) {
            continue;
        }
        dictionary.push_back(temp);
        if (i >= 1) {
            i = i - 1;
        }
    }
    return answer;
}
int main() {
    vector<int> answe1r;
    answe1r=solution("TOBEORNOTTOBEORTOBEORNOT");
    for (int i = 0; i < answe1r.size(); i++) {
        cout << answe1r[i] << '\n';
    }
    
}

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

 

16953번: A → B

첫째 줄에 A, B (1 ≤ A < B ≤ 109)가 주어진다.

www.acmicpc.net

이 문제의 경우 사실 dfs로푸는게 간단해보였다 하지만 문제 분류가 그리디로 되어있었으니 그리디로 풀어 보겠다

이문제의 경우 A와 B가 주어졌을 경우 A에서 B를 만든다고 생각하지말고 B에서 A로 가야한다고 생각해야 잘풀리는 문제였다 B가 일단 2로 나누어지는 경우 2로 나누고 B가 10으로 나누었을 때 1이 남으면 10으로 나눈다 그후 A와 비교해서 같으면 나오고 아니면 다시 실행한다 단 B가 A보다 작아졌을 경우는 문제의 답이 존재하지 않는 경우기 때문에 -1을

출력한다.

이문제의 경우 상당히 쉬웠지만 계속 A에서 B를 만들려고 하니 시간이 많이 소모되었다.

#include <iostream>
using namespace std;
int main() {
	int A, B;
	int countnum=0;
	cin >> A >> B;
	while (true) {
		if (A == B) {
			countnum += 1;
			break;
		}
		if (A > B) {
			countnum= -1;
			break;
		}
		if (B % 10 == 1) {
			B--;
			B = B / 10;
			countnum++;
		}
		else if (B % 2 == 0) {
			B = B / 2;
			countnum++;
		}
		else {
			countnum= -1;
			break;
		}
	}
	cout << countnum;

}

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

백준 1202  (0) 2024.07.27
백준 2437  (0) 2024.07.20
백준 13904  (0) 2024.07.18
백준 1715  (1) 2023.01.08
백준 1946  (0) 2022.12.20

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

 

11052번: 카드 구매하기

첫째 줄에 민규가 구매하려고 하는 카드의 개수 N이 주어진다. (1 ≤ N ≤ 1,000) 둘째 줄에는 Pi가 P1부터 PN까지 순서대로 주어진다. (1 ≤ Pi ≤ 10,000)

www.acmicpc.net

이 문제의 경우 여러방면으로 풀려고 시도 했으나 결국 또 점화식을 계속 이상하게 세워서 빨리 풀지 못했다

이 문제는 점화식만 처음에 방향을 잘잡고 풀었으면 빨리 풀렸을 거 같은 문제였다 일단 이문제는

카드를 1장만 산다고 생각해서 카드 개수를 늘려가면서 점화식을 세우는게 효율적이 었던거 같다.

이 문제의 dp배열은 해당 인덱스 장만큼의 카드를 살때의 최댓값을 나타낸다.

일단 dp배열을 초기화 할때 각배열에 그 장만큼의 카드를 살 때의 가격을 넣어준다

일단 카드 1장을 살 때는 경우의 수가 카드 1장짜리를 사는 경우의 수밖에 없으니  팩의 최댓값을 나타내는 dp[1]의 값이 밑에 처럼된다

dp[1]= 1장 짜리 카드팩의 가격

이런식으로 넣는다

dp[2]= 1장을 샀을 때의 최댓값 +1장을 샀을 때의 최댓값 와 2팩짜리를 샀을 때 중 큰 값을 골라준다

dp[3]= 2장을 샀을때의 최댓값 + 1장 짜리 샀을때의 최댓값과  3팩짜리를 샀을 때의 최댓값을 비교해서 큰값을 골라준다

dp[4] 부터는 경우의  수가 많아진다 

dp[4]= 1장을 삿을때의 최댓값사고 3장을 샀을 떄의 최댓값, 2장을 샀을 때의 최댓값 + 2장을 샀을때의 최댓값 4팩짜리를 샀을 때의 값중 최댓값을 골라서 넣어준다 이것을 간단히 식으로 나타내면

dp[1]=dp[1];

dp[2]=max(dp[1]+dp[1],dp[2])

dp[3]=max(dp[1]+dp[2],dp[2]+dp[1],dp[3])

dp[4]=max(dp[1]+dp[3],dp[2]+dp[2],dp[3]+dp[1],dp[4]) 

이런식으로 규칙성이 발생해서 점화식을 만들수 있다

#include <iostream>
#include <algorithm>
using namespace std;
int dp[1001];
int main() {
	int N;
	cin >> N;
	for (int i = 1; i <= N; i++) {
		cin >> dp[i];
	}
	for (int i = 2; i <= N/2; i++) {
		for (int j = 1; j < i; j++) {
			dp[i] = max(dp[i], dp[j] + dp[i - j]);
		}
	}
	cout << dp[N];
}

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

백준 12865  (0) 2023.01.08
백준 9465  (0) 2022.12.28
백준 10844  (0) 2022.12.19
백준 2156  (0) 2022.12.19
백준 1912  (0) 2022.12.19

 

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

 

24480번: 알고리즘 수업 - 깊이 우선 탐색 2

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

www.acmicpc.net

이문제의 경우도 DFS의 개념을 알기에는 좋은 문제였다 DFS의 경우 자신과 연결된 자식들중 하나에게로 간다음 계속 쭉 갔다가 자신의 부모로 돌아오는 게 핵심이다 DFS의 자식들이 오름차순으로 정렬 되어 있을수도 있고 내림차순으로 정렬 되어있을 수도 있다. 이전 문제는 오름차순으로 정렬해놓고 시작했다면 이번 문제에서는 내림차순으로 정렬하여 큰수 부터 방문하도록 하였다.

 

 

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector <int> vertex[100001];
int visited[100001];
int visitedRank[100001];
int countnum=0;
void dfs(int start) {
	if (visited[start] == false) {
		visited[start] = true;
		countnum += 1;
		visitedRank[start] = countnum;
		int sizeofvertex = vertex[start].size();
		for (int i = 0; i < sizeofvertex; i++) {
			if (visited[vertex[start][i]] == false) {
				dfs(vertex[start][i]);
			}
		}
	}

}
int main() {
	int vertexnum, edgenum, startvertex;
	cin >> vertexnum >> edgenum >> startvertex;
	
	for (int i = 1; i <= edgenum; i++) {
		int temp1,temp2;
		cin >> temp1>>temp2;
		vertex[temp2].push_back(temp1);
		vertex[temp1].push_back(temp2);
	}
	for (int i = 1; i <= vertexnum; i++) {
		sort(vertex[i].rbegin(), vertex[i].rend());
	}
	dfs(startvertex);
	for (int i = 1; i <= vertexnum; i++) {
		cout << visitedRank[i] << '\n';
	}
}

자 코드를 한번 보자

내가 dfs에서 가장 좋아하는 방법은 vector로 선언하여 입력 받은 값들을 차례로 서로의 정점 번호를 index로 하는 vector에 서로서로를 넣는 방식이다 

for (int i = 1; i <= edgenum; i++) {
		int temp1,temp2;
		cin >> temp1>>temp2;
		vertex[temp2].push_back(temp1);
		vertex[temp1].push_back(temp2);
	}

그래서 이부분의 코드가 이렇게 되는 것이다 입력을 받았으면 지금 두정점이 연결된것이기 때문에 자기로 부터 연결되는 vector를 모두 넣어야하기 때문에 1-2 이렇게 연결되어있다면 2번 vertex 에는 1을 1번 vertex에는 2를 넣어 준다 그후 코드는 vector를 내림차순으로 정렬해준것이다 원래 벡터를 오름 차순으로 정렬할때는 vertex.begin과 vertex.end를 쓰지만 내림차순으로 정렬할 때는 rbegin과 rend를 써주면 내림 차순으로 정렬 한다 

void dfs(int start) {
	if (visited[start] == false) {
		visited[start] = true;
		countnum += 1;
		visitedRank[start] = countnum;
		int sizeofvertex = vertex[start].size();
		for (int i = 0; i < sizeofvertex; i++) {
			if (visited[vertex[start][i]] == false) {
				dfs(vertex[start][i]);
			}
		}
	}

}

그후 dfs코드는 이전에 첨부한 다른 문제와 비슷하다 일단 내가 방분하려고 하는 점이 방문된적이 없다면 그점을 방문했다고 true로 마크하고 방문한 번째수를 1증가시키고 해당정점의 등수를visitedRank에 표시해준다 그다음 그정점의 자식들 즉 vector에 있는 값들을 순회하면서 방문하지 않았던 좌표에 방문 한다.

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

백준 1012  (0) 2022.12.29
백준 1697  (0) 2022.12.27
백준 24479  (0) 2022.12.20
백준 2178  (0) 2022.12.18
백준 1260  (1) 2022.12.17

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

 

1946번: 신입 사원

첫째 줄에는 테스트 케이스의 개수 T(1 ≤ T ≤ 20)가 주어진다. 각 테스트 케이스의 첫째 줄에 지원자의 숫자 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N개 줄에는 각각의 지원자의 서류심사 성

www.acmicpc.net

이 문제는 풀다가 이상하다 왤케 답이 완전 다르게 나오지 하다가 보니까 내가 문제를 잘못이해하고 있었다

2
5
3 2
1 4
4 1
2 3
5 5
7
3 6
7 3
4 2
1 4
5 7
2 5
6 1

 

여기 나오는 이값들은 사실 순위였던 것이었다. 그래서 문제를 이상하게 풀고 있었다. 이문제는 간단히 설명하자면

하나의 성적을 기준으로 줄을 세워놓은 다음에 다음애들을 비교하여 그 줄에서 나의 다음(나보다 성적이 낮은) 애들의 다른 성적을 비교하여 나보다 성적이 낮으면 그친구를 쳐내는 방식이다 예를 들면 서류심사 성적으로 줄을 세워놓은 다음에

나보다 서려심사를 못봤는데 나보다 면접 성적 까지 낮으면 그 사람은 세지 않는 방법이다

자 위 그림을 보자 서류 성적 순대로 정렬 한다 이렇게 정렬하면 내 다음에 나오는 애는 무조건 나보다 서류 성적은 낮은 상태가 된다. 그러므로 나보다 서류성적이 낮은애랑 나의 면접성적을 비교한다 나의 다음애가 나보다 면접 성적이 높으니 count를 하고 지금까지 비교했을 때 가장 높은 성적을 maxnum에 저장해주고 countnum을 하나 증가시켜준다 즉 현재 서류성적순으로 정렬했을때 가장 높은 면접성적은 3등이다 이제 그다음에 나오는 애는 3등보다 면접 성적이 높으면 maxnum에 갱신해주고 쳐내지 않지만  다음애가 이전까지 비교해서 나온성적인 3등보다 낮으면 쳐낸다 계속 이렇게 반복하여 countnum의 값을 답으로 출력해주면 된다

#include <iostream>
#include <algorithm>
using namespace std;
pair<int, int> score[100000];
int answer[20];
int main() {
	int testnum;
	cin >> testnum;
	for (int i = 0; i < testnum; i++) {
		int countnum = 0;
		int candidatenum;
		cin >> candidatenum;
		for (int j = 0; j < candidatenum; j++) {
			cin >> score[j].first >> score[j].second;
		}
		sort(score, score + candidatenum);
		int maxscore = score[0].second;

		for (int j = 0; j < candidatenum; j++) {
			if (score[j].second <= maxscore) {
				countnum++;
				maxscore = score[j].second;
			}

		}
		answer[i] = countnum;
	}
	for (int i = 0; i < testnum; i++) {
		cout << answer[i] << '\n';
	}
}

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

백준 1202  (0) 2024.07.27
백준 2437  (0) 2024.07.20
백준 13904  (0) 2024.07.18
백준 1715  (1) 2023.01.08
백준 16953  (0) 2022.12.26

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

+ Recent posts