안녕하세요, 여행벌입니다.

오늘은 자바 컬렉션프레임워크에 대해서 포스팅해보도록 하겠습니다.


컬렉션프레임워크

 자바에서 말하는 컬렉션 프레임워크는 "데이터의 저장 방법, 이와 관련 있는 알고리즘들을 잘 정의해놓은 클래스들의 구조" 라고 얘기할 수 있습니다.

 즉, 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 자료구조와 알고리즘들을 지원해주는 자바 프레임워크입니다!

컬렉션프레임워크 기본구조

 컬렉션프레임워크의 인터페이스들은 다음과 같은 기본 골격을 가지고 있습니다.

 Map 인터페이스를 제이하고 모두 Iterable 인터페이스와 Collection 인터페이스를 상속하고 있는 구조입니다.

컬렉션클래스

 '컬렉션 클래스' 들은 컬렉션 인터페이스 Set, List, Queue, Map 를 구현한 클래스들을 의미합니다. Vector 클래스, Hashtable 클래스와 같이 자바 초기부터 존재하는 컬렉션 클래스들도 있지만, 이전 코드와의 호환성 유지를 위해 존재하는 클래스일 뿐입니다. 이 클래스들은 성능 저하의 원인이 되기도 하므로 아직도 유용하게 사용되거나 새롭게 추가된 더 좋은 컬렉션 클래스들만 차근차근 정리해보도록 하겠습니다.

인터페이스별 특징

인터페이스 설명 클래스
List<E> / Queue<E> 순서가 있는 데이터 집합으로, 중복 데이터를 허용한다 ArrayList, LinekdList, Queue, Deque
Set<E> 순서가 없는 데이터 집합으로, 중복 데이터를 허용하지
않는다.
HashSet, TreeSet
Map<K,V> 순서가 없는 <Key, Value> 쌍의 데이터 집합으로 Key의
중복을 허용하지 않는다.
HashMap, TreeMap

 크게 위의 표와 같이 3가지 인터페이스로 나눠볼 수 있습니다. 물론, List<E> / Queue<E> 인터페이스는 서로 다른 인터페이스입니다!


컬렉션 프레임워크의 컬렉션 클래스들을 잘 사용한다면

상황에 맞는 자료구조와 알고리즘을 쉽게 사용할 수 있습니다.

차근차근 컬렉션 클래스들과 알고리즘을 정리해보도록 하겠습니다.

안녕하세요, 여행벌입니다.

간단하게 STS 다크 테마 적용하는 법에 대해 정리해보겠습니다.


 처음에 STS를 설치하면 다음과 같은 기본 테마가 설정되어있습니다.

  상단의 Window -> Preferences 를 누르면 다음과 같은 창이 나옵니다.

 왼쪽의 General -> Appearance 로 들어가시면 다음과 같이 테마를 설정할 수 있습니다.

 Dark로 설정하시면 다크 테마를 적용할 수 있습니다.


 

문제 : https://www.acmicpc.net/problem/18809


문제해석

 Green, Red 배양액을 땅에 뿌리고, 배양액이 주변으로 퍼져나가며, Green / Red 배양액이 만나게 되면 Flower가 생긴다.

문제핵심

1. 가능한 땅 중에서 Green, Red 배양액을 무조건 다 뿌려야 된다.

--> Backtracking 을 이용해서 가능한 모든 경우를 구해봐야 한다.

2. Green, Red 배양액이 단순히 만나는 게 아니라 동일한 시간에 도달한 땅에서만 Flower 가 생긴다.

--> 단순히 BFS 탐색만을 진행하면 안 된다.

알고리즘

1. 입력받은 map에서 배양액을 뿌릴 수 있는 vitaminMap을 따로 모아둔다.

2. 백트레킹을 통해 vitaminMap에 Green, Red 배양액을 다 뿌린다.

3. BFS 탐색을 통해서 Green, Red 배양액을 뿌려나갈 건데 다음과 같은 stateMap을 이용한다.

pair<int, int> stateMap[i][j] = (i, j) 에서 { 현재 시간, 현재 상태 } 를 저장한다.

--> 초기 배양액을 뿌린 곳들만 stateMap[i][j] = { 0, Green || Red } 로 초기화한다.

--> BFS 탐색을 통해서 현재 지점에서 다음 지점들로 탐색을 진행해나가는데, 

● 다음 지점의 stateMap 의 상태가 EMPTY 면 Green, Red 배양액이 아직 뿌려지지 않은 Map이므로 Green, Red 배양액을 저장해준다.

 다음 지점의 stateMap 상태가 Green 이고 현재 상태가 Red 이고 같은 시간에 방문했다면 Flower 를 만듭니다.

 다음 지점의 stateMap 상태가 Red 이고 현재 상태가 Green 이고 같은 시간에 방문했다면 Flower 를 만듭니다.

알고리즘회고

 처음에는 stateMap 을 이용할 생각을 못하고, 현재 queue에 저장된 Green, Red 에서 다음 지점들을 다 탐색해나가며 nextGreen, nextRed 라고 다음 지점들을 다 따로 저장했다. 그 후, 따로 저장한 지점들을 비교하며 Flower가 만들어지는 지점들을 체크하고 아닌 지점들은 다시 queue에 Push 해주는 방식으로 BFS 탐색을 진행했다. 당연히 시간이 위의 알고리즘에 비해 오래 걸렸고 BarkingDog 님의 코드를 참고해서 알고리즘을 개선할 수 있었다.

#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;

int N, M, G, R, ans;
int map[50][50]; // 0 은 호수 3은 레드 4는 그린
int dx[4] = { -1, 0, 1, 0 }, dy[4] = { 0, -1, 0, 1 };
vector<pair<int, int>> vitaminMap;
int vitamin[10]; // 0은 아무것도 안뿌림 1은 레드 2는 그린

const int EMPTY = 0;
const int RED = 3;
const int GREEN = 4;
const int FLOWER = 5;

bool check(int r, int c) {
	if (0 <= r && r < N && 0 <= c && c < M) return true;
	return false;
}

void BFS() {
	int result = 0;
	pair<int, int> state[50][50];
	queue<pair<int, int>> q;
	for (int i = 0; i < vitaminMap.size(); i++) {
		if (vitamin[i] == 0) continue;
		state[vitaminMap[i].first][vitaminMap[i].second] = { 0, vitamin[i] };
		q.push(vitaminMap[i]);
	}
	while (!q.empty()) {
		int curX = q.front().first, curY = q.front().second;
		int curT = state[curX][curY].first, curC = state[curX][curY].second;
		q.pop();
		if (curC == FLOWER) continue;
		for (int dir = 0; dir < 4; dir++) {
			int nX = curX + dx[dir], nY = curY + dy[dir];
			if (!check(nX, nY)) continue; // 범위 밖
			if (map[nX][nY] == 0) continue; // 호수
			if (state[nX][nY].second == EMPTY) {
				state[nX][nY] = { curT + 1, curC };
				q.push({ nX, nY });
			}
			else if (state[nX][nY].second == RED) {
				if (curC == GREEN && state[nX][nY].first == curT + 1) {
					result++;
					state[nX][nY].second = FLOWER;
				}
			}
			else if (state[nX][nY].second == GREEN) {
				if (curC == RED && state[nX][nY].first == curT + 1) {
					result++;
					state[nX][nY].second = FLOWER;
				}
			}
		}
	}
	ans = max(ans, result);
	return;
}

void Backtracking(int s, int curG, int curR) {
	if (curG == G && curR == R) {
		BFS();
		return;
	}
	for (int i = s; i < vitaminMap.size(); i++) {
		if (vitamin[i] == 0 && curG < G) {
			vitamin[i] = GREEN;
			Backtracking(i + 1, curG + 1, curR);
			vitamin[i] = 0;
		}
		if (vitamin[i] == 0 && curR < R) {
			vitamin[i] = RED;
			Backtracking(i + 1, curG, curR + 1);
			vitamin[i] = 0;
		}
	}
	return;
}

int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	cin >> N >> M >> G >> R;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < M; j++){
			cin >> map[i][j];
			if (map[i][j] == 2) vitaminMap.push_back({ i, j });
		}

	Backtracking(0, 0, 0);

	cout << ans << '\n';
	return 0;
}

 

문제 : https://www.acmicpc.net/problem/3109


문제해석

 왼쪽끝에서 오른쪽끝으로 파이프를 연결해 길을 만들고 싶은데, 파이프끼리 겹치면 안되고 파이프는 오른쪽, 오른쪽 대각선 위, 오른쪽 대각선 아래 로 이어서 설치할 수 있다. 길을 최대 몇 개 만들 수 있을까?

문제핵심

 1. 현재 지점에서 파이프를 연결해 길을 만들 때, 아래에서 시작하는 다른 길과 겹치지않으려면 제일 좋은 이동은 오른쪽 대각선 위 > 오른쪽 > 오른쪽 대각선 아래 가 된다. 우리는 그냥 길을 최대한 많이 만들면 되므로 Greedy 하게 위에서부터 길을 만들어가면 된다.

 2. 일반적인 DFS 탐색은 탐색하고 돌아오면 visited 배열을 다시 초기화해주나, 이 문제에서는 방문해서 끝에 도달하지 못한 경로는 다른 지점에서 방문해도 어차피 끝에 도달하지 못하므로 visited 배열을 다시 초기화 해줄 필요가 없고, 초기화해준다면 경로가 겹쳐서 시간초과에 직면하게 됩니다.

알고리즘

 왼쪽 위에서부터 시작해서 DFS 탐색을 진행한다. 우선 순위가 높은 오른쪽 대각선 위, 오른쪽, 오른쪽 대각선 아래 순으로 탐색을 진행하고 끝에 도달하게 된다면 S 지점에서 끝에 도달했다고 checked 를 한다. 그 후, S 지점에서 시작하던 탐색들을 다 종료한다. 재귀적으로 탐색을 하고 돌아왔다는 사실은 그 길로는 오른쪽 끝에 도달하지 못한다는 것을 의미한다. 따라서, visited 배열을 초기화하지 않고 그대로 남겨두어 다른 경로에서 이 지점을 탐색하는 불필요한 연산을 줄여주면 시간초과를 피할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include<iostream>
 
using namespace std;
 
int R, C, ans;
int dx[3= { -101 }, dy[3= { 111 };
bool checked[10000];
bool visited[10000][500];
char map[10000][501];
 
void DFS(int s, int x, int y) {
    if (y == C - 1) {
        ans++;
        checked[s] = 1;
        return;
    }
    
    for (int i = 0; i < 3; i++) {
        int nX = x + dx[i], nY = y + dy[i];
        if (!(0 <= nX && nX < R && 0 <= nY && nY < C)) continue;
        if (visited[nX][nY]) continue;
        if (map[nX][nY] == 'x'continue;
 
        visited[nX][nY] = 1;
        DFS(s, nX, nY);
        if (checked[s]) return;
    }
}
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
 
    cin >> R >> C;
    for (int i = 0; i < R; i++)
        cin >> map[i];
 
    for (int i = 0; i < R; i++){    
        visited[i][0= 1;
        DFS(i, i, 0);
    }
    cout << ans << '\n';
    return 0;
}
cs

 

'Problem Solving > BOJ' 카테고리의 다른 글

[BOJ] 15906 : 변신 이동 게임  (0) 2020.07.06
[BOJ] 18809 : Gaaaaaaaaaarden  (0) 2020.07.02
[BOJ] 15681 : 트리와 쿼리  (0) 2020.07.01
[BOJ] 18235 : 지금 만나러 갑니다  (0) 2020.06.25
[BOJ]15591 : MooTube(Silver)  (0) 2020.06.22

+ Recent posts