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

 

2583번: 영역 구하기

첫째 줄에 M과 N, 그리고 K가 빈칸을 사이에 두고 차례로 주어진다. M, N, K는 모두 100 이하의 자연수이다. 둘째 줄부터 K개의 줄에는 한 줄에 하나씩 직사각형의 왼쪽 아래 꼭짓점의 x, y좌표값과 오

www.acmicpc.net

 

풀이 과정

 꼭짓점 좌표에 따라서 사각형을 맵에 기록하고 최종적으로 mp값이 0인 연결 컴포넌트의 개수와 각 컴포넌트의 크기를 구하는 문제였다. 꼭짓점 좌표를 입력받고 시작 꼭짓점 이상 마지막 꼭짓점 미만으로 mp에 값을 입력했다. dfs()에서 노드 하나를 방문하고 종료되면 cnt++를 수행하며 컴포넌트의 크기를 구했다.

 

느낀 점

 문제에 2가지 포인트가 있었다고 생각한다. 첫 째는 DFS를 구현할 때 리턴값을 활용할 줄 아는가, 둘 째는 꼭짓점이 가지는 의미를 알고 이를 이용해 잘 입력받았는가 이다. 나는 두 번째를 뒤늦게 알아차려 시간이 조금 소요되었다. 꼭짓점과 칸의 인덱스를 매치 해봤을 때, 시작 꼭짓점에 해당하는 좌표의 칸은 직사각형 안에 포함 되지만, 마지막 꼭짓점 좌표에 해당하는 칸은 포함되지 않는다. 따라서 시작 꼭짓점 이상, 종료 꼭짓점 미만으로 사각형 범위를 지정하고 값을 채워나가야 했다. 섬세하게 생각해 볼 수 있는 기회가 됬다.

 

#include<bits/stdc++.h>
using namespace std;

const int MAX = 101;
int n, m, k, cnt;
int mp[MAX][MAX], visited[MAX][MAX];
int my[4] = { 1, 0 , -1, 0 }, mx[4] = { 0, 1, 0, -1 };
vector<int> ret;

int dfs(int y, int x) {
	if (mp[y][x] != 0 || visited[y][x]) return 0;
	visited[y][x] = 1;
	for (int i = 0; i < 4; i++) {
		int ny = my[i] + y;
		int nx = mx[i] + x;
		if (ny < 0 || ny >= n || nx < 0 || nx >= m) continue;
		dfs(ny, nx);
	}
	cnt++;
	return cnt;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	//입력
	cin >> n >> m >> k;
	for (int i = 0; i < k; i++) {
		int fy, fx, ly, lx;
		cin >> fx >> fy >> lx >> ly;
		for (int j = fy; j < ly; j++) {
			for (int z = fx; z < lx; z++) {
				mp[j][z]++;
			}
		}
	}
	
	/* 입력 테스트
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cout << mp[i][j] << " ";
		}
		cout << "\n";
	}
	*/

	//수행
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cnt = 0;
			int temp = dfs(i, j);
			if(temp) ret.push_back(temp);
		}
	}
	//정렬
	sort(ret.begin(), ret.end());
	//출력
	cout << ret.size() << "\n";
	for (int i = 0; i < ret.size(); i++) cout << ret[i] << " ";
	return 0;
}

'알고리즘 : C++ > BaekJoon' 카테고리의 다른 글

백준 2828번 - 사과 담기 게임  (0) 2023.05.20
백준 1992번 - 쿼드트리  (0) 2023.05.20
백준 2468번 - 안전 영역  (0) 2023.05.20
백준 1012번 - 유기농 배추  (0) 2023.05.20
백준 2178번 - 미로 탐색  (0) 2023.05.20

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

 

2468번: 안전 영역

재난방재청에서는 많은 비가 내리는 장마철에 대비해서 다음과 같은 일을 계획하고 있다. 먼저 어떤 지역의 높이 정보를 파악한다. 그 다음에 그 지역에 많은 비가 내렸을 때 물에 잠기지 않는

www.acmicpc.net

 

풀이 과정

 비가 내리는 양에 따라 침수, 비침수로 영역이 구분되고, 이때 비침수 지역의 연결 컴포넌트 개수 중 최대치를 구하는 문제이다. 이전에 풀었던 '유기농 배추' 문제와 같이 연결 컴포넌트를 구하는 문제이지만, 탐색 조건에 변화를 주며(비 내리는 양) 최대치를 갱신해야하는 문제였다. 아에 오지 않는 경우부터 모든 건물이 침수 되기 전까지 for문을 이용해 탐색했다. 이전과 마찬가지로 연결 컴포넌트를 구할 때는 DFS를 이용해 탐색이 성공하면 1을 리턴하고 cnt++를 하며 연결 컴포넌트 개수를 구했고, 최종적을 max(ret, cnt)로 최댓값을 갱신했다. 이때 내리는 비의 양이 바뀔 때마다 visited와 cnt를 초기화 했다. 비가 아에 내리지 않는 경우부터 모든 건물이 침수 되기 직전까지(모두 침수되면 0개, 비가 오지 않으면 1개이기 때문에) 구하기 위해서 k를 0이상, 건물 최대높이 이하 조건까지 탐색했고, 건물 높이와 비의 양이 같은 경우는 침수되지 않는 것으로 판단했다. 

 

느낀 점

 초기화를 수행할 때 visited뿐 아니라 mp까지 초기화하는 실수, dfs()인자에 i와 j 인덱스가 아닌 0, 0을 넣는 실수를 해서 디버깅하느라 애를 먹었다. 체화해서 빠르게 하는 것도 중요하지만, 실수 하는 부분들은 내가 완전히 체화되지 않은 부분이라 생각하고 신중히 신경써야겠다.

 

#include<bits/stdc++.h>
using namespace std;

const int MAX = 101;
int n, cnt, rmx, ret, temp;
int mp[MAX][MAX], visited[MAX][MAX];
int my[4] = { 1, 0 , -1, 0 }, mx[4] = { 0, 1, 0, -1 };

//DFS로 연결된 컴포넌트 완전 탐색
bool dfs(int y, int x, int r) {
	if (visited[y][x] || r > mp[y][x]) return 0;
	visited[y][x] = 1;
	for (int i = 0; i < 4; i++) {
		int ny = y + my[i];
		int nx = x + mx[i];
		if (ny < 0 || ny >= n || nx < 0 || nx >= n || visited[ny][nx]) continue;
		dfs(ny, nx, r);
	}
	return 1;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	//입력
	cin >> n;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cin >> temp;
			mp[i][j] = temp;
			rmx = max(rmx, temp);
		}
	}
	//수행, 비가 내리는 양이 k일 때 연결 컴포넌트
	for (int k = 0; k <= rmx; k++) {
		//초기화
		fill(&visited[0][0], &visited[100][100], 0);
		cnt = 0;
		//컴포넌트 개수 카운트
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if(dfs(i, j, k)) cnt++;
			}
		}
		//최댓값 갱신
		ret = max(ret, cnt);
	}
	//출력
	cout << ret << "\n";
	return 0;
}

'알고리즘 : C++ > BaekJoon' 카테고리의 다른 글

백준 1992번 - 쿼드트리  (0) 2023.05.20
백준 2583번 - 영역 구하기  (0) 2023.05.20
백준 1012번 - 유기농 배추  (0) 2023.05.20
백준 2178번 - 미로 탐색  (0) 2023.05.20
백준 1627번 - 곱셈  (0) 2023.05.20

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

 

1012번: 유기농 배추

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

www.acmicpc.net

 

풀이 과정

 애벌레가 상하좌우만 이동 가능할 때,  총 몇 마리의 애벌레가 있어야 전체 배추를 방문할 수 있는지에 대한 문제이다. 연결 컴포넌트를 찾는 문제로, 배열 전체를 방문하며 완전 탐색을 수행한다. 탐색을 하며 방문한 배열에 visitied 표시를 해주고 중복되어 방문하지 않도록 한다. 모든 mp요소에 DFS를 수행한다. 방문하지 않았던 배열의 경우 DFS를 수행해 visited를 1로 바꿔주고 하나의 컴포넌트 방문이 끝나면 1을 리턴하고 cnt에 더해준다. 이미 방문한 컴포넌트 요소에는 다시 방문하지 않기 때문에 최종적으로 cnt는 연결 컴포넌트 개수가 된다.

 

느낀 점

 처음에 int형 2차원 배열들에 대해서 'C3863'에러가 발생했다. 관련된 배열을 참조하는 함수를 찾다 fill() 함수에서 문제가 있을 것이라 생각해, memset()함수로 바꾸어 실행한 결과 정상적으로 작동했다. fill() 함수로 2차원 (혹은 다차원) 배열을 초기화 할 때 단순히 'fill(&mp[0], &mp[0] + 51, 0)이라 한 것이 문제였다. 지금 생각해보면 위 함수가 실행된다해도 2차원 배열 중 첫 째줄 배열에만 초기화가 적용되니 잘못된 것이 당연했다. fill(&mp[0][0], &mp[50][50], 0)이 올바른 초기화 법이고, 0이나 1로 초기화 할 때는 memset() 이용하는 것도 기억해두자.

 

#include<bits/stdc++.h>
using namespace std;

const int MAX = 51;
int n, m, k, t, ky, kx, cnt;
int mp[MAX][MAX], visited[MAX][MAX];
int my[4] = { 1, 0 , -1, 0 }, mx[4] = { 0, 1, 0, -1 };

//DFS 완전 탐색(하나의 연결 컴포넌트 방문)
bool dfs(int y, int x) {
	if (visited[y][x] || !mp[y][x]) return 0;
	visited[y][x] = 1;
	for (int i = 0; i < 4; i++) { //4방향 탐색
		int ny = y + my[i];
		int nx = x + mx[i];
		if (ny < 0 || ny >= n || nx < 0 || nx >= m || visited[ny][nx] || !mp[ny][nx]) continue;
		dfs(ny, nx);
	}
	return 1;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	cin >> t;
	for (int T = 1; T <= t; T++) {
    	//초기화
		n = 0; m = 0; k = 0; ky = 0; kx = 0; cnt = 0;
		//memset(mp, 0, 51);
		//memset(visited, 0, 51);
		fill(&mp[0][0], &mp[50][50], 0);
		fill(&visited[0][0], &visited[50][50], 0);
		//입력
		cin >> m >> n >> k;
		for (int i = 0; i < k; i++) {
			cin >> kx >> ky;
			mp[ky][kx] = 1;
		}
		//수행
		for (int i = 0; i < n; i ++) {
			for (int j = 0; j < m; j++) {
				cnt += dfs(i, j);
			}
		}
		//출력
		cout << cnt << "\n";
	}
	return 0;
}

'알고리즘 : C++ > BaekJoon' 카테고리의 다른 글

백준 2583번 - 영역 구하기  (0) 2023.05.20
백준 2468번 - 안전 영역  (0) 2023.05.20
백준 2178번 - 미로 탐색  (0) 2023.05.20
백준 1627번 - 곱셈  (0) 2023.05.20
백준 4375번 - 1  (0) 2023.05.19

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

 

2178번: 미로 탐색

첫째 줄에 두 정수 N, M(2 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 M개의 정수로 미로가 주어진다. 각각의 수들은 붙어서 입력으로 주어진다.

www.acmicpc.net

 

풀이 과정

 1과 0으로 이루어진 미로의 (0, 0)에서 (n - 1, m - 1)까지 최단 거리를 구하는 문제이다. 이때 가중치가 1로 일정하므로 BFS를 사용해서 문제를 풀었다. QUEUE를 이용해 BFS를 구현할 때, 이전 visited + 1 을 해줌으로서 첫 노드와 탐색 노드의 거리를 구했다.

 

느낀 점

 DFS를 주로 사용하다가 BFS를 사용하려하니 곧바로 코드가 생각나지 않았다. 하지만 큐와 4방향 탐색을 통해 찾아간다는 개념을 기반으로 천천히 구현하다보니 자연스럽게 구현되었다.

 

#include<bits/stdc++.h>
using namespace std;

int n, m;
char mp[101][101];
int visited[101][101];
int my[4] = { 1, 0, -1, 0 }, mx[4] = { 0, 1, 0, -1 };

void bfs(int y, int x) {
	//큐생성과 초기값 할당
	queue<pair<int, int>> q;
	q.push({ y, x });
	visited[y][x] = 1;

	while (q.size()) {
		for (int i = 0; i < 4; i++) { //4방향 탐색
			int ny = q.front().first + my[i];
			int nx = q.front().second + mx[i];
			if (ny < 0 || ny >= n || nx < 0 || nx >= m || visited[ny][nx] || mp[ny][nx] == '0') continue;
			q.push({ ny, nx });
			visited[ny][nx] = visited[q.front().first][q.front().second] + 1;
		}
		if(!q.empty()) q.pop();
	}
	return;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	//입력
	cin >> n >> m;

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> mp[i][j];
		}
	}
	//수행
	bfs(0, 0);
	//출력
	cout << visited[n - 1][m - 1];

	return 0;
}

'알고리즘 : C++ > BaekJoon' 카테고리의 다른 글

백준 2468번 - 안전 영역  (0) 2023.05.20
백준 1012번 - 유기농 배추  (0) 2023.05.20
백준 1627번 - 곱셈  (0) 2023.05.20
백준 4375번 - 1  (0) 2023.05.19
백준 3986번 - 좋은 단어  (0) 2023.05.19

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

 

1629번: 곱셈

첫째 줄에 A, B, C가 빈 칸을 사이에 두고 순서대로 주어진다. A, B, C는 모두 2,147,483,647 이하의 자연수이다.

www.acmicpc.net

 

풀이 과정

 모듈러 연산과 분할 정복을 알아야 풀 수 있다. '( A  *  B ) % C = ( A % C ) * ( B % C ) % C' 와  2^2 * 2^2 = 2^4 와 같은 사실을 이용한다. 재귀 함수를 만들어 b번 일어날 연산을 log(2)b (로그 2의 b)번 까지 줄여준다. b == 1이 되면 돌아오도록 조건을 걸고, 재귀를 빠져나오며 연산이 수행된다. 연산이 수행될 때는 수가 너무 커지지 않도록 모듈러 연산 개념을 이용해서 수를 계속 줄여준다. 그리고 마지막 리턴 전에 b가 홀수라면 a를 1회 더 곱해줘야하므로 b%2 == 1일 경우 a를 한번 더 곱하고 모듈러 연산 해주었다.

 

느낀 점

 다른 문제도 마찬가지지만 비슷한 문제를 몇번 풀어보며 체화해야될 것이라 보인다. 결국 다른 사람들의 코드를 참고한 후 풀 수 있었고 기본적인 수학 개념을 보충해야될 필요성을 느꼈다. 또 분할 정복과 모듈러 연산은 연산 횟수를 획기적으로 줄이기 때문에 반드시 짚고 가야할 개념이다.

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a, b, c, ret;

ll re(ll a, ll b, ll c) {
	if (b == 1) return a % c;
	ll temp = re(a, b / 2, c);
	temp = (temp % c) * (temp % c) % c;
	if (b % 2 == 1)temp = (temp % c) * (a % c) % c;
	return temp;
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	cin >> a >> b >> c;

	ret = re(a, b, c);

	cout << ret << "\n";

	return 0;
}

'알고리즘 : C++ > BaekJoon' 카테고리의 다른 글

백준 1012번 - 유기농 배추  (0) 2023.05.20
백준 2178번 - 미로 탐색  (0) 2023.05.20
백준 4375번 - 1  (0) 2023.05.19
백준 3986번 - 좋은 단어  (0) 2023.05.19
백준 1940번 - 주몽  (0) 2023.05.19

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

 

4375번: 1

2와 5로 나누어 떨어지지 않는 정수 n(1 ≤ n ≤ 10000)가 주어졌을 때, 각 자릿수가 모두 1로만 이루어진 n의 배수를 찾는 프로그램을 작성하시오.

www.acmicpc.net

 

풀이 과정

 입력 받은 n을 111....1까지 만드는 것이 아니라 1부터 시작해서 11, 111, 1111...을 n으로 나눠 0이되는 자릿수를 찾아야한다. 어떻게 보면 역발상이 필요하다고 할 수도 있다. 

 

느낀 점

 숫자와 관련된 문제가 나오면 어떤 복잡한 규칙을 찾기에만 매진하게 된다. 일단은 단순하게 구현할 수 있는 방법은 없는지 먼저 생각해보자.

 

#include<bits/stdc++.h>
using namespace std;

int n, a, cnt;

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	while (cin >> n) {
		a = 0; cnt = 0;
		do {
			cnt++;
			a = (a * 10) + 1;
			a %= n;
		} while (a != 0);
		cout << cnt << "\n";
	}
	
	return 0;
}

'알고리즘 : C++ > BaekJoon' 카테고리의 다른 글

백준 2178번 - 미로 탐색  (0) 2023.05.20
백준 1627번 - 곱셈  (0) 2023.05.20
백준 3986번 - 좋은 단어  (0) 2023.05.19
백준 1940번 - 주몽  (0) 2023.05.19
백준 1213번 - 팰린드롬 만들기  (0) 2023.05.19

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

 

3986번: 좋은 단어

이번 계절학기에 심리학 개론을 수강 중인 평석이는 오늘 자정까지 보고서를 제출해야 한다. 보고서 작성이 너무 지루했던 평석이는 노트북에 엎드려서 꾸벅꾸벅 졸다가 제출 마감 1시간 전에

www.acmicpc.net

 

풀이 과정

 스택을 이용해서 풀었다. 문자를 앞에서 부터 스택에 넣는다. 이때 스택의 top과 다음번 문자가 같다면 top을 pop()해준다. 최종적으로 스택이 비어있다면 좋은 단어로 분류되고 cnt++를 수행한다.

 

느낀 점

 처음 문제를 풀 때는 스택을 떠올리지 못해 오랜 시간 고민했었다. 브루트포스와 여러 자료 구조들이 문제에 필요한 건 아닌지 생각해보고, 다양한 자료 구조 유형의 문제를 풀어볼 필요가 있다.

 

#include<bits/stdc++.h>
using namespace std;

int n, cnt; 
stack<char> stk;
string s;

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> s;
		for (int j = 0; j < s.size(); j++) {
			if (!stk.empty() && stk.top() == s[j]) stk.pop();
			else stk.push(s[j]);
		}
		if (stk.empty()) cnt++;
		
		while (!stk.empty()) stk.pop();
	}
	//출력
	cout << cnt << "\n";
	return 0;
}

'알고리즘 : C++ > BaekJoon' 카테고리의 다른 글

백준 1627번 - 곱셈  (0) 2023.05.20
백준 4375번 - 1  (0) 2023.05.19
백준 1940번 - 주몽  (0) 2023.05.19
백준 1213번 - 팰린드롬 만들기  (0) 2023.05.19
백준 9375번 - 패션왕 신해빈  (0) 2023.05.19

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

 

1940번: 주몽

첫째 줄에는 재료의 개수 N(1 ≤ N ≤ 15,000)이 주어진다. 그리고 두 번째 줄에는 갑옷을 만드는데 필요한 수 M(1 ≤ M ≤ 10,000,000) 주어진다. 그리고 마지막으로 셋째 줄에는 N개의 재료들이 가진 고

www.acmicpc.net

 

풀이 과정

 n개의 재료를 입력받고 두 재료의 합이 m이 되는 경우의 수를 구하는 문제이다. 문제에서는 '만들 수 있는 갑옷의 수'라고 했지만, 재료의 번호는 고유하다는 뜻이 재료가 번호 당 하나씩만 있다는 뜻이라 문제가 모호했다고 생각한다. for문을 사용해 2개의 재료 조합을 탐색하며 합이 m이 되는 경우 cnt++을 수행했다.

 

느낀 점

 두 번째 푸는 문제라 바로 풀었지만, 아무리 봐도 문제가 모호해서 헷갈릴 법하다. 질문 게시판에도 비슷한 글이 있는 걸로 봐서는 수정이 필요할 듯하다.

 

#include<bits/stdc++.h>
using namespace std;

vector<int> input;
int n, m, temp, cnt;

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	//입력
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		cin >> temp;
		input.push_back(temp);
	}
	//탐색
	for (int i = 0; i < n - 1; i++) {
		for (int j = i + 1; j < n; j++) {
			if (input[i] + input[j] == m) cnt++;
		}
	}
	//출력
	cout << cnt <<"\n";

	return 0;
}

+ Recent posts