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

 

2667번: 단지번호붙이기

<그림 1>과 같이 정사각형 모양의 지도가 있다. 1은 집이 있는 곳을, 0은 집이 없는 곳을 나타낸다. 철수는 이 지도를 가지고 연결된 집의 모임인 단지를 정의하고, 단지에 번호를 붙이려 한다. 여

www.acmicpc.net

이러한 문제류는 이제 dfs든 bfs로 풀기 쉬워졌다 이문제의 경우 자신을 기준으로 상하좌우로만 이동 할 수있기때문에 깊이우선 탐색으로 풀어 보았다 이문제는 어차피 단지의 개수를 세야 하기때문에 모든점을 한번에 다방문하면서 개수를 셀수 있는 dfs를 사용하였다. 이문제의 핵심 부분은

	if ((!visited[i][j + 1]) && map[i][j+1]==1)
		dfs(i, j + 1);
	if ((!visited[i][j - 1]) && map[i][j - 1]==1)
		dfs(i, j - 1);
	if ((!visited[i - 1][j]) && map[i-1][j]==1)
		dfs(i - 1, j);
	if ((!visited[i + 1][j]) && map[i + 1][j]==1)
		dfs(i + 1, j);

이부분이다 나를 기준으로 내 상하좌우중 방문한적이 없는 애들이 없으면 방문한다 그후 이함수 부분을 재귀적으로 호출하기 때문에 내 다음애들이 없으면 다시 부모로 돌아가서 다음거를 탐색한다 즉 재귀함수로 dfs를 구현한것이다

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int map[26][26];
bool visited[26][26];
int countnum = 0;
int danjicount = 0;
vector<int> answer;
void dfs(int i, int j) {
	countnum++;
	visited[i][j] = true;
	if ((!visited[i][j + 1]) && map[i][j+1]==1)
		dfs(i, j + 1);
	if ((!visited[i][j - 1]) && map[i][j - 1]==1)
		dfs(i, j - 1);
	if ((!visited[i - 1][j]) && map[i-1][j]==1)
		dfs(i - 1, j);
	if ((!visited[i + 1][j]) && map[i + 1][j]==1)
		dfs(i + 1, j);
}
int main() {
	int N;
	string temp;
	cin >> N;
	for (int i = 1; i <= N; i++) {
		cin >> temp;
		for (int j = 0; j <N; j++) {
			map[i][j + 1] = temp[j]-'0';
		}
	} 

	for (int i = 1; i <= N; i++) {	
		for (int j = 1; j <= N; j++) {
			countnum = 0;
			if (visited[i][j] || map[i][j]==0)
				continue;
			dfs(i, j);
			danjicount++;
			if(countnum)
				answer.push_back(countnum);
		}
	}
	
	sort(answer.begin(), answer.end());
	cout << danjicount << '\n';
	for (int i = 0; i < answer.size(); i++) {
		cout << answer[i] << '\n';
	}

}

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

백준 14940  (1) 2023.06.08
백준 11724  (0) 2023.06.01
백준 1012  (0) 2022.12.29
백준 1697  (0) 2022.12.27
백준 24480  (1) 2022.12.21

 

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

 

1012번: 유기농 배추

차세대 영농인 한나는 강원도 고랭지에서 유기농 배추를 재배하기로 하였다. 농약을 쓰지 않고 배추를 재배하려면 배추를 해충으로부터 보호하는 것이 중요하기 때문에, 한나는 해충 방지에 

www.acmicpc.net

이문제는 요즘 나의 경악스러운 알고리즘 실력에 실망하던차에 내가 빠르게 풀 수 있는 문제였다. 아직  고수가 되긴 멀었지만 빨리 이런 문제쯤은 10분만에 해치울 수 있는 파워 프로그래머가 되고 싶다!!!!!

이 문제의 경우 여러방식으로 풀 수 있다. 나의 경우 일반적으로 성능이 나쁘지 않은 BFS를 사용해서 풀었다 

자 이문제를 풀때는 처음 1인애를 만나면 루프를 돌면서 자신을 기준으로 갈 수 있는 모든 점들을 BFS로 접근하여 visited배열에 마킹합니다 visited 배열이 1로 마킹되면 다시 해당하는 곳을 접근 하지 않습니다 이렇게 빨간색으로 체크 된 1을 root로 나머지 1로마킹된 애들이 BFS 로서 빨갛게 1로 마킹된 애들부터 같은색깔안에 있는 영역으로 접근합니다.

#include <iostream>
#include <queue>
using namespace std;
bool cabbage[52][52];
int visited[52][52];
int main() {
	int T; //테스트 케이스의 개수
	int M, N, K;//M:가로길이 N:세로길이 K: 배추가 심어져있는 위치의 개수;'
	cin >> T;
	queue<pair<int, int>> bfsQueue;
	for (int i = 0; i < T; i++) {
		cin >> M >> N >> K;
		for (int j = 0; j < M; j++) {
			for (int k = 0; k < N; k++) {
				cabbage[j][k] = 0;
				visited[j][k] = 0;
			}
		}
		for (int j = 0; j < K; j++) {
			int temp1, temp2;
			cin >> temp1 >> temp2;
			cabbage[temp1][temp2] = 1;
		}
		int countnum = 0;
		for (int j = 0; j < M; j++) {
			for (int k = 0; k < N; k++) {
				if (visited[j][k] == 1 && cabbage[j][k]==1)
					continue;
				else if(visited[j][k]==0 && cabbage[j][k]==1){
					countnum += 1;
					cabbage[j][k] = 1;
					bfsQueue.push(pair<int, int>(j, k));
					while (!bfsQueue.empty()) {
						int firstn,secondn;
						firstn = bfsQueue.front().first;
						secondn = bfsQueue.front().second;
						bfsQueue.pop();
						if (firstn >= 1) {
							if (visited[firstn - 1][secondn]==0 &&cabbage[firstn-1][secondn] == 1) {
								bfsQueue.push(pair<int, int>(firstn - 1, secondn));
								visited[firstn - 1][secondn] = 1;
							}
						}
						if (secondn >= 1) {
							if (visited[firstn][secondn - 1] == 0 && cabbage[firstn][secondn - 1]==1) {
								bfsQueue.push(pair<int, int>(firstn, secondn - 1));
								visited[firstn][secondn - 1] = 1;
							}
						}
						if (visited[firstn + 1][secondn] == 0 && cabbage[firstn + 1][secondn]==1) {
							bfsQueue.push(pair<int, int>(firstn + 1, secondn));
							visited[firstn + 1][secondn] = 1;
						}
						if (visited[firstn ][secondn+1] == 0 && cabbage[firstn][secondn + 1]==1) {
							bfsQueue.push(pair<int, int>(firstn , secondn+1));
							visited[firstn][secondn + 1] = 1;
						}
					}
				}
			}
			
		}
		cout << countnum << '\n';
	}
}
		for (int j = 0; j < M; j++) {
			for (int k = 0; k < N; k++) {
				cabbage[j][k] = 0;
				visited[j][k] = 0;
			}
		}
		for (int j = 0; j < K; j++) {
			int temp1, temp2;
			cin >> temp1 >> temp2;
			cabbage[temp1][temp2] = 1;
		}

일단 이부분은 각 케이스의 접근할때 배열들을 초기화 한후 양배추가 위치한곳을 1로 체크해줍니다

for (int k = 0; k < N; k++) {
				if (visited[j][k] == 1 && cabbage[j][k]==1)
					continue;
				else if(visited[j][k]==0 && cabbage[j][k]==1){
					countnum += 1;
					cabbage[j][k] = 1;
					bfsQueue.push(pair<int, int>(j, k));
					while (!bfsQueue.empty()) {
						int firstn,secondn;
						firstn = bfsQueue.front().first;
						secondn = bfsQueue.front().second;
						bfsQueue.pop();
						if (firstn >= 1) {
							if (visited[firstn - 1][secondn]==0 &&cabbage[firstn-1][secondn] == 1) {
								bfsQueue.push(pair<int, int>(firstn - 1, secondn));
								visited[firstn - 1][secondn] = 1;
							}
						}
						if (secondn >= 1) {
							if (visited[firstn][secondn - 1] == 0 && cabbage[firstn][secondn - 1]==1) {
								bfsQueue.push(pair<int, int>(firstn, secondn - 1));
								visited[firstn][secondn - 1] = 1;
							}
						}
						if (visited[firstn + 1][secondn] == 0 && cabbage[firstn + 1][secondn]==1) {
							bfsQueue.push(pair<int, int>(firstn + 1, secondn));
							visited[firstn + 1][secondn] = 1;
						}
						if (visited[firstn ][secondn+1] == 0 && cabbage[firstn][secondn + 1]==1) {
							bfsQueue.push(pair<int, int>(firstn , secondn+1));
							visited[firstn][secondn + 1] = 1;
						}
					}
				}
			}

이부분은 모든 배열을 돌면서 visited배열이 1로된 위치이거나 양배추가 심어지지않는 cabbage 가 0인쪽은 방문하지 않게 합니다 만약에 visited가 0이고 cabbage가 1이면 방문하게 합니다 그후 BFS를 위해 큐에다가 각각의 자식들을 집어넣고 

BFS를 실행하여 인접한 모든 cabbage가 1인 요소들에 대하여 visited 배열을 1로 초기화 해줍니다

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

백준 11724  (0) 2023.06.01
백준 2667  (0) 2023.01.02
백준 1697  (0) 2022.12.27
백준 24480  (1) 2022.12.21
백준 24479  (0) 2022.12.20

https://school.programmers.co.kr/learn/courses/30/lessons/12939

 

프로그래머스

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

programmers.co.kr

프로그래머스를 풀면서 느끼고 있는게 기업 코테에서 문자열 처리가 은근 많이 나오는거 같다 그래서 나도 기존에 c++로 문자열 파싱까지 했었는데 문자열 관련 구현은 c++ 로 하기에는 시간적으로 많이 부족한거 같다. 이에 기본적으로 문자열 처리에 많은 도움을 주는 파이썬을 사용해서 문자열 처리 문제는 앞으로 처리 하기로 했다 실제로 c++로 구현하면 엄청 오래걸릴 코드들도 파이썬의 문자열 인덱싱 기능만 사용하면 빠른시간안에 끝난다. 이번문제는 이러한 이유로 파이썬으로 풀었다 c++로 풀고싶지는 않다 이러한 문제를 일단 이문제는 그냥 쉽다 파이썬의 split을 이용해서 빈칸으로 각 요소들을을 분할해주고 그 list들의 요소들의 값을 서로 비교해서 최대 최솟값을 구한다이다. 아마도 코드를 보면 이해가 쉽게 될 것 이다

def solution(s):
    answer = ''
    a = []
    s = s.split(' ')
    for i in s:
        a.append(int(i))

    max=a[0]
    min=a[0]
    for i in a:
        if i >max:
            max=i
        if i<min:
            min=i
    answer=answer+str(min)
    answer=answer+" "
    answer=answer+str(max)
    return answer

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

+ Recent posts