PRIM 알고리즘

MST(최소 신장 트리)를 구현하는 방법으로는 크루스칼 알고리즘과 프림 알고리즘이 있다.

오늘은 프림 알고리즘에 대해 더 자세히 살펴보도록 하겠다.

 

프림 알고리즘을 시작점을 중심으로 방문 가능한 모든 정점을 방문해서 가장 최소 가중치를 가지는 노드와 연결하고,

이를 모든 정점을 방문할 때 까지 반복함으로써 최소 신장 트리를 구한다.

 

크루스칼은 프림에 비해 희소 그래프인 경우, 그러니까 간선이 적은 경우 적합하고,

프림은 크루스칼에 비해 간선이 많이 존재하는 밀집그래프에 더 적합하다.

 

크루스칼 알고리즘은 아래에서 더 자세하게 다룬다.

https://jinniepark.tistory.com/55

 

[알고리즘 기본]Kruskal 알고리즘

Kruskal 알고리즘 MST(최소 신장 트리)를 구현하는 방법으로는 크루스칼 알고리즘과 프림 알고리즘이 있다. 오늘은 크루스칼 알고리즘에 대해 더 자세히 살펴보도록 하겠다. 크루스칼 알고리즘은

jinniepark.tistory.com

 

일단을 개념적으로 구하는 방법을 그려보았다.


예시)

 

 

초기 상태이다. 해당 정점을 방문했는지 체크할 visited배열과 가장 작은 가중치를 가질 Min_edge배열이 존재한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

하지만 위와 같은 방법으로 구현 할 때 인접해 있는 노드를 탐색하고 또 그 가중치를 비교하는 과정에서 정렬/비교를 하면 (주변 정점 수)-1번 만큼 연산이 이루어져야한다. 이는 많은 노드와 정점이 있다면 시간복잡도를 늘리는 원인이 된다.

따라서 실제 구현할때는 우선순위 큐를 사용해서 시간복잡도를 줄여야한다. 

 

아래에 우선순위 큐를 추가한 구현방법을 확인해보겠다.

 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


관련문제

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

 

1197번: 최소 스패닝 트리

첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선의 개수 E(1 ≤ E ≤ 100,000)가 주어진다. 다음 E개의 줄에는 각 간선에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 이는 A번 정점과 B번 정점이

www.acmicpc.net

https://jinniepark.tistory.com/47

 

[백준][1197]최소 스패닝 트리

/* 문제설명 */ 최소 스패닝 트리는, 주어진 그래프의 모든 정점들을 연결하는 부분 그래프 중에서 그 가중치의 합이 최소인 트리를 말한다. 입력 첫째 줄에 정점의 개수 V(1 ≤ V ≤ 10,000)와 간선

jinniepark.tistory.com

 

 

 

/* 문제설명 */

세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다.

말은 상하좌우로 인접한 네 칸 중의 한 칸으로 이동할 수 있는데, 새로 이동한 칸에 적혀 있는 알파벳은 지금까지 지나온 모든 칸에 적혀 있는 알파벳과는 달라야 한다. 즉, 같은 알파벳이 적힌 칸을 두 번 지날 수 없다.

좌측 상단에서 시작해서, 말이 최대한 몇 칸을 지날 수 있는지를 구하는 프로그램을 작성하시오. 말이 지나는 칸은 좌측 상단의 칸도 포함된다.

입력

첫째 줄에 R과 C가 빈칸을 사이에 두고 주어진다. (1 ≤ R,C ≤ 20) 둘째 줄부터 R개의 줄에 걸쳐서 보드에 적혀 있는 C개의 대문자 알파벳들이 빈칸 없이 주어진다.

출력

첫째 줄에 말이 지날 수 있는 최대의 칸 수를 출력한다.

 

 

 


 

 

 

/* 풀이방법 */

백트래킹을 활용해서 풀이했다.

이미 지나온 알파벳인가 아닌가 판별하기 위해 ArrayList를 썼다가 시간초과가 났다.

(+)컬렉션의 시간복잡도에 대해 공부해야겠다는 필요성을 느꼈다.

http://kwseo.github.io/2015/09/24/time-complexity-about-collections/

그래서 boolean배열을 하나 만들어 이미 접근한 알파벳인지 알아보는데 썼다.

이러한 형태인데, 0은 A, 1는 B . . . 25는 Z와 매칭된다.

false인 상태면 아직 해당 알파벳이 접근한 적이 없다는 뜻이고, true이면 해당 알파벳을 이미 지나왔다는 뜻이다.

 

시작점 (0, 0)으로부터 탐색할 수 있는 깊이 만큼 DFS를 사용해서 탐색하고, 맨끝 노드에 도달했다면

지금까지의 count를 max와 비교한다. 

그리고 해당 DFS를 빠져나오면 다음 노드를 탐색하기위해 방금 그 노드의 접근 기록을 지운다

방금 노드의 alpa를 다시 false로 만들고, count도 1 뺀다.

 

상하좌우 순으로 순회하므로 다음과 같은 Map에서 아래와 같은 상황이 노드 끝까지 순회한 상황이다.

더이상 순회 할 수 없으므로 count를 max와 비교하고 해당 노드를 빠져나온다.

(왼)해당 순회 끝 (오)백트래킹

그러면 다음과 같이 백트래킹 과정이 일어나게 된다. 해당 노드를 방문하기 전으로 돌리는 것이다.

 

 

 

 


 

/* 해답코드 */

package baekjoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class b1987 {
	public static int[] dr = { -1, 1, 0,0};	//상하좌우
	public static int[] dc = { 0, 0, -1,1 };
	public static int R;
	public static int C;
	public static int max=0;
	public static int count=1;
	public static char[][] map;
	public static boolean[] alpa = new boolean[26];
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		R = Integer.parseInt(st.nextToken());
		C = Integer.parseInt(st.nextToken());
		map = new char[R][C];
		for (int r = 0; r < R; r++) {
			map[r] = br.readLine().toCharArray();
		}
		alpa[(int)map[0][0]-65]=true;
		dfs(0,0);
		System.out.println(max);
	}
	
	public static void dfs(int r, int c) {
		for(int d=0;d<4;d++) {
			int nr = r+dr[d];
			int nc = c+dc[d];
			if(nr>=0&&nr<R&&nc>=0&&nc<C&&!alpa[(int)map[nr][nc]-65]) {	
				alpa[(int)map[nr][nc]-65]=true;
				count++;
				dfs(nr,nc);	
				alpa[(int)map[nr][nc]-65]=false;
				count--;	
			}
			if(d==3) {
				if(max < count)
					max = count;			
			}
		}
	}
}

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준][16236]아기상어  (0) 2021.08.25
[백준][1197]최소 스패닝 트리  (0) 2021.08.24
[백준][3109]빵집  (0) 2021.08.19
[백준][1992]쿼드트리  (0) 2021.08.18
[백준][1074]Z  (0) 2021.08.17

/* 문제설명 */

유명한 제빵사 김원웅은 빵집을 운영하고 있다. 원웅이의 빵집은 글로벌 재정 위기를 피해가지 못했고, 결국 심각한 재정 위기에 빠졌다.

원웅이는 지출을 줄이고자 여기저기 지출을 살펴보던 중에, 가스비가 제일 크다는 것을 알게되었다. 따라서 원웅이는 근처 빵집의 가스관에 몰래 파이프를 설치해 훔쳐서 사용하기로 했다.

빵집이 있는 곳은 R*C 격자로 표현할 수 있다. 첫째 열은 근처 빵집의 가스관이고, 마지막 열은 원웅이의 빵집이다.

원웅이는 가스관과 빵집을 연결하는 파이프를 설치하려고 한다. 빵집과 가스관 사이에는 건물이 있을 수도 있다. 건물이 있는 경우에는 파이프를 놓을 수 없다.

가스관과 빵집을 연결하는 모든 파이프라인은 첫째 열에서 시작해야 하고, 마지막 열에서 끝나야 한다. 각 칸은 오른쪽, 오른쪽 위 대각선, 오른쪽 아래 대각선으로 연결할 수 있고, 각 칸의 중심끼리 연결하는 것이다.

원웅이는 가스를 되도록 많이 훔치려고 한다. 따라서, 가스관과 빵집을 연결하는 파이프라인을 여러 개 설치할 것이다. 이 경로는 겹칠 수 없고, 서로 접할 수도 없다. 즉, 각 칸을 지나는 파이프는 하나이어야 한다.

원웅이 빵집의 모습이 주어졌을 때, 원웅이가 설치할 수 있는 가스관과 빵집을 연결하는 파이프라인의 최대 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 R과 C가 주어진다. (1 ≤ R ≤ 10,000, 5 ≤ C ≤ 500)

다음 R개 줄에는 빵집 근처의 모습이 주어진다. '.'는 빈 칸이고, 'x'는 건물이다. 처음과 마지막 열은 항상 비어있다.

출력

첫째 줄에 원웅이가 놓을 수 있는 파이프라인의 최대 개수를 출력한다.

유명한 제빵사 김원웅은 빵집을 운영하고 있다. 원웅이의 빵집은 글로벌 재정 위기를 피해가지 못했고, 결국 심각한 재정 위기에 빠졌다.

원웅이는 지출을 줄이고자 여기저기 지출을 살펴보던 중에, 가스비가 제일 크다는 것을 알게되었다. 따라서 원웅이는 근처 빵집의 가스관에 몰래 파이프를 설치해 훔쳐서 사용하기로 했다.

빵집이 있는 곳은 R*C 격자로 표현할 수 있다. 첫째 열은 근처 빵집의 가스관이고, 마지막 열은 원웅이의 빵집이다.

원웅이는 가스관과 빵집을 연결하는 파이프를 설치하려고 한다. 빵집과 가스관 사이에는 건물이 있을 수도 있다. 건물이 있는 경우에는 파이프를 놓을 수 없다.

가스관과 빵집을 연결하는 모든 파이프라인은 첫째 열에서 시작해야 하고, 마지막 열에서 끝나야 한다. 각 칸은 오른쪽, 오른쪽 위 대각선, 오른쪽 아래 대각선으로 연결할 수 있고, 각 칸의 중심끼리 연결하는 것이다.

원웅이는 가스를 되도록 많이 훔치려고 한다. 따라서, 가스관과 빵집을 연결하는 파이프라인을 여러 개 설치할 것이다. 이 경로는 겹칠 수 없고, 서로 접할 수도 없다. 즉, 각 칸을 지나는 파이프는 하나이어야 한다.

원웅이 빵집의 모습이 주어졌을 때, 원웅이가 설치할 수 있는 가스관과 빵집을 연결하는 파이프라인의 최대 개수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 R과 C가 주어진다. (1 ≤ R ≤ 10,000, 5 ≤ C ≤ 500)

다음 R개 줄에는 빵집 근처의 모습이 주어진다. '.'는 빈 칸이고, 'x'는 건물이다. 처음과 마지막 열은 항상 비어있다.

출력

첫째 줄에 원웅이가 놓을 수 있는 파이프라인의 최대 개수를 출력한다.

 

 

 

 


 

 

 

/* 풀이방법 */

DFS탐색을 사용해서 풀었다.

파이프 시작부분을 돌면서 DFS를 구현한 재귀함수를 돈다. 오른쪽 위, 오른쪽, 오른쪽 아래 순으로 탐색하게 된다.

만약 아직 해당 파이프가 출발지에 도착하지 못했다면 방문했다는 표시로 "X"를 표시한다.

이미 도착한 이후는 순회할 필요가 없으므로, successed라는 전역 boolean 변수를 생성하여 도착했을때 true로 바꿔준다.

그러면 다음 파이프 출발지를 시작하기 전까지는 남은 재귀함수를 순회한다거나 방문을 표시하지 않는다.

 

 

1번째 줄 파이프를 순회한 모습

 

2번째 줄 파이프를 순회한 모습

 

3번째 줄 파이프를 순회한 모습

 

4번째 줄 파이프를 순회한 모습

 

마지막 줄은 방문할 수 있는 곳이 없다!

그래서 완주에 성공한 개수인 2가 출력되게 된다.

 

 

 


 

/* 해답코드 */

package baekjoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

//빵집
public class b3109 {
	public static int[] dr = { -1, 0, 1 };
	public static int R;
	public static int C;

	public static int result = 0;
	public static boolean successed;
	public static String[][] map;

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		R = Integer.parseInt(st.nextToken());
		C = Integer.parseInt(st.nextToken());
		map = new String[R][C];

		for (int r = 0; r < R; r++) {
			String[] temp = br.readLine().split("");
			map[r] = temp;
		}
		for (int i = 0; i < R; i++) {
			successed = false;
			dfs(i, 0);
		}
		System.out.println(result);

	}

	public static void dfs(int r, int c) {
		if(successed) {
			return;
		}
		else if(c==C-1) {
			successed=true;
			result++;
			return;
		}
		
		for(int d=0; d<3; d++) {
			
			int nr = r+dr[d];
			int nc = c+1;
			
			if(nr>=0&&nr<R&&!map[nr][nc].equals("x")) {
				if(!successed)
					map[nr][nc]="x";
				dfs(nr,nc);
				
			}
		}
	}
}

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준][1197]최소 스패닝 트리  (0) 2021.08.24
[백준][1987]알파벳  (1) 2021.08.19
[백준][1992]쿼드트리  (0) 2021.08.18
[백준][1074]Z  (0) 2021.08.17
[백준]선물 전달  (0) 2021.08.16

 

 

/* 문제설명 */

흑백 영상을 압축하여 표현하는 데이터 구조로 쿼드 트리(Quad Tree)라는 방법이 있다. 흰 점을 나타내는 0과 검은 점을 나타내는 1로만 이루어진 영상(2차원 배열)에서 같은 숫자의 점들이 한 곳에 많이 몰려있으면, 쿼드 트리에서는 이를 압축하여 간단히 표현할 수 있다.

주어진 영상이 모두 0으로만 되어 있으면 압축 결과는 "0"이 되고, 모두 1로만 되어 있으면 압축 결과는 "1"이 된다. 만약 0과 1이 섞여 있으면 전체를 한 번에 나타내지를 못하고, 왼쪽 위, 오른쪽 위, 왼쪽 아래, 오른쪽 아래, 이렇게 4개의 영상으로 나누어 압축하게 되며, 이 4개의 영역을 압축한 결과를 차례대로 괄호 안에 묶어서 표현한다

위 그림에서 왼쪽의 영상은 오른쪽의 배열과 같이 숫자로 주어지며, 이 영상을 쿼드 트리 구조를 이용하여 압축하면 "(0(0011)(0(0111)01)1)"로 표현된다.  N ×N 크기의 영상이 주어질 때, 이 영상을 압축한 결과를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에는 영상의 크기를 나타내는 숫자 N 이 주어진다. N 은 언제나 2의 제곱수로 주어지며, 1 ≤ N ≤ 64의 범위를 가진다. 두 번째 줄부터는 길이 N의 문자열이 N개 들어온다. 각 문자열은 0 또는 1의 숫자로 이루어져 있으며, 영상의 각 점들을 나타낸다.

출력

영상을 압축한 결과를 출력한다.

 

 

 


 

 

 

/* 풀이방법 */

첫번째 값만 저장해놓고 해당 사이즈만큼 전체를 순회하다가 첫번째 값과 다른 값이 발견되면

사이즈를 1/2로 줄이고, 현재지점을 x,y라 할때

 

1사분면 - (x,y)부터 줄여진 사이즈만큼 순회

2사분면 - (x,y+사이즈)부터 줄여진 사이즈 만큼 순회

3사분면 - (x+사이즈,y)부터 줄여진 사이즈 만큼 순회

4사분면 - (x+사이즈,y+사이즈)부터 줄여진 사이즈 만큼 순회

 

다음과 같이 재귀 호출 한다.

 

해당 사이즈만큼의 크기가 모두 같은 값이거나, 사이즈가 1이라면 해당 숫자를 프린트 한다.

 

 


 

/* 해답코드 */

package baekjoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

//쿼드트리
public class b1992 {
	public static String[][] map;
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(br.readLine());
		map = new String[N][N];
		for(int i=0;i<N;i++) {
			map[i]=br.readLine().split("");
		}		
		quadTree(N,0,0);
	}
	public static void quadTree(int size,int x,int y) {
		String start = map[x][y];
		if(size==1) {
			System.out.print(start);
			return;
		}
		
		for(int i=x;i<x+size;i++) {
			for(int j=y;j<y+size;j++) {
				if(!start.equals(map[i][j])) {
					size/=2;
					System.out.print("(");
					quadTree(size,x,y);
					quadTree(size,x,y+size);
					quadTree(size,x+size,y);
					quadTree(size,x+size,y+size);
					System.out.print(")");
					return;
				}
			}
		}
		System.out.print(start);
	}
	
}

 

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준][1987]알파벳  (1) 2021.08.19
[백준][3109]빵집  (0) 2021.08.19
[백준][1074]Z  (0) 2021.08.17
[백준]선물 전달  (0) 2021.08.16
[백준]1,2,3 더하기  (0) 2021.08.14

 

 

/* 문제설명 */

http://jungol.co.kr/bbs/board.php?bo_table=pbank&wr_id=1101&sca=30

아래의 풀이는 문제에 있는 테스트 케이스를 기준으로 설명하였다!

 


 

 

 

/* 풀이방법 */

 

일단 음식을 입력받아 arr에 모두 추가했다.

정렬을 하기위해 Food class는 Comparable을 상속받았고

최소온도 오름차순, 같다면 최고온도 오름차순으로 비교되도록 compareTo메소드를 구현했다.

그럼 다음과 같이 정렬되어 있게 된다.

 

 

 

 

 

그리고 스택을 하나 만들어서 (이때 스택의 한 요소는 냉장고를 의미한다)

첫번째 음식을 푸쉬한다.

그러면 해당 이제 저 냉장고(스택의 요소)는

-15 ~ 5도 사이의 온도를 유지하는 냉장고라는 의미이다.

 

이제 그다음 부터 arr에 있는 모든 음식을 순서대로 돌면서 냉장고와 값을 비교하면 된다.

 

 

 

 

 

 

 

 

 

배열에 있는 두번째 값을 스택에 있는 냉장고와 비교한다.

최저 온도가 더 높은 것으로 변경하고, 최고 온도 또한 더 낮은것으로 변경한다.

(그래야 두 음식에게 모두 적합한 온도가 되니까)

 

그래서 스택의 냉장고의 온도는 다음과 같이 변하게 된다.

만약 해당 범위를 넘어서는 음식이 들어온다면 그 음식은 현재 냉장고에 추가할 수 없으므로 새로운 요소를 스택에 추가 시키고 범위를 그 음식의 범위로 한다.

 

 

 

 

 

3번째 음식]

 

 

 

[4번째 음식]

 

그래서 스택의 사이즈인 2개의 냉장고가 필요하다.

 

 

 


 

/* 해답코드 */

package jungol;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Stack;
import java.util.StringTokenizer;

class Food implements Comparable<Food>{
	public int low;
	public int high;
	public Food() {}
	public Food(int low, int high) {
		super();
		this.low = low;
		this.high = high;
	}
	@Override
	public int compareTo(Food o) {
		if(this.low == o.low)
			return this.high - o.high;
		return this.low - o.low;
	}
}

public class j1828 {
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;
		int N = Integer.parseInt(br.readLine());
		Food[] arr = new Food[N];
		Stack<Food> ref = new Stack<Food>();;
		
		for(int i=0;i<N;i++) {
			st = new StringTokenizer(br.readLine());
			int low = Integer.parseInt(st.nextToken());
			int high = Integer.parseInt(st.nextToken());  
			arr[i] =new Food(low,high);
		}
		Arrays.sort(arr);
		ref.push(arr[0]);
		for(int i=1;i<N;i++) {
			boolean contain = false;
			Food f = ref.pop();

			if(f.low<=arr[i].low&&f.high>=arr[i].low) {
				f.low = arr[i].low;
				contain = true;
			}
				
			if(f.high>=arr[i].high&&f.low<=arr[i].high) {
				f.high = arr[i].high;
				contain = true;
			}

			ref.push(f);
			if(!contain) {
				ref.push(arr[i]);
			}
		}
		System.out.println(ref.size());
		
	}
}

 

 

/* 문제설명 */

한수는 크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 한다. 예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다.

만약, N > 1이 라서 왼쪽 위에 있는 칸이 하나가 아니라면, 배열을 크기가 2N-1 × 2N-1로 4등분 한 후에 재귀적으로 순서대로 방문한다.

다음 예는 22 × 22 크기의 배열을 방문한 순서이다.

N이 주어졌을 때, r행 c열을 몇 번째로 방문하는지 출력하는 프로그램을 작성하시오.

다음은 N=3일 때의 예이다.

입력

첫째 줄에 정수 N, r, c가 주어진다.

출력

r행 c열을 몇 번째로 방문했는지 출력한다.

 

 

 

 


 

 

 

/* 풀이방법 */

 

분할 정복방식으로 풀었다. Z모양 배열을 보면 아래와 같은 모양이 반복됨을 알 수 있다.

따라서 3행 1열에 있는 숫자를 구하고 싶다면,

처음 사이즈에서 3사분면 내의 4 사분면에 위치하고 있는 것이다.

따라서 while문안에 size를 나누기2 해가면서 탐색을 해갔다.

 

(+)

1사분면의 첫번째 값 = num의 변화 없음

2사분면의 첫번째 값 = num + ((현재사이즈/2) * (현재사이즈/2)) * 2

3사분면의 첫번째 값 = num + ((현재사이즈/2) * (현재사이즈/2)) * 3

4사분면의 첫번째 값 = num + ((현재사이즈/2) * (현재사이즈/2)) * 4

 

 

 


 

/* 해답코드 */

package baekjoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class b1074 {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		int N = Integer.parseInt(st.nextToken());
		int r = Integer.parseInt(st.nextToken());
		int c = Integer.parseInt(st.nextToken());
		
		
		int size = (int)Math.pow(2, N);
		int cr = 0;
		int cc = 0;
		int num  =0;
		while(true) {
			if(cr==r&&cc==c) {
				break;
			}
			
			if(r<(size/2+cr)) {
				//2번
				if(c>=(size/2+cc)){
					num += Math.pow(size/2, 2);
					cc+=size/2;
				}
			}else {
				//3번
				if(c<(size/2+cc)) {
					num += Math.pow(size/2, 2)*2;
					cr+=size/2;
				}
				//4번
				else {
					num += Math.pow(size/2, 2)*3;
					cr+=size/2;
					cc+=size/2;
				}
			}			
			size = size/2;
		}
		
		System.out.println(num);
		
	}

}

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준][3109]빵집  (0) 2021.08.19
[백준][1992]쿼드트리  (0) 2021.08.18
[백준]선물 전달  (0) 2021.08.16
[백준]1,2,3 더하기  (0) 2021.08.14
[백준]설탕배달  (0) 2021.08.14

/* 문제설명 */

이번 ACM-ICPC 대회에 참가한 모든 사람들은 선물을 하나씩 준비했다.

대회가 끝나고 난 후에 각자 선물을 전달하려고 할 때, 선물을 나누는 경우의 수를 구하는 프로그램을 작성하시오.

모든 사람은 선물은 하나씩 받으며, 자기의 선물을 자기가 받는 경우는 없다.

입력

첫째 줄에 ACM-ICPC 대회에 참가한 학생의 수 N(1≤N≤1,000,000)이 주어진다.

출력

경우의 수를 1,000,000,000으로 나눈 나머지를 첫째 줄에 출력한다.

 

 

 

 


 

 

 

/* 풀이방법 */

 

 

완전순열


 

/* 해답코드 */

package baekjoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class b1947 {

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(br.readLine());
		int[] M = new int[1000001];
		int answer = 0;
		if(N==1) {
			answer=0;
		}else if(N==2) {
			answer=1;
		}else {
			M[1] = 0;
			M[2] = 1;
			for(int i =3;i<=N;i++) {
				long temp = ((long)(i-1) * ((M[i-1] + M[i-2])))%1000000000;
				M[i] = (int)temp;
			}
			answer = M[N];
		}
		
		
		System.out.println(answer);
	}
}

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준][1992]쿼드트리  (0) 2021.08.18
[백준][1074]Z  (0) 2021.08.17
[백준]1,2,3 더하기  (0) 2021.08.14
[백준]설탕배달  (0) 2021.08.14
[백준]개미  (0) 2021.08.08

/* 문제설명 */

정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다.

  • 1+1+1+1
  • 1+1+2
  • 1+2+1
  • 2+1+1
  • 2+2
  • 1+3
  • 3+1

정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 n이 주어진다. n은 양수이며 11보다 작다.

출력

각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 출력한다.

 

 

 


 

 

 

/* 풀이방법 */

전형적인 DP문제로, 메모이제이션 기법을 사용해서 풀었다.

d[1] = { 1 } = 1가지

d[2] = { 1+1 , 2 } = 2가지

d[3] = { 1+1+1 , 1+2 , 2+1 , 3 } = 4가지

위에 문제를 보면 d[4] = 7가지 임을 알 수있다. 이를 미루어 보아 

d[n] = d[n] + d[n-1] + d[n-2]

이러한 점화식을 세울 수 있다.

                         

 


 

/* 해답코드 */

package baekjoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

//dp의 시작
//1,2,3더하기
public class b9095 {
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int T = Integer.parseInt(br.readLine());
		int[] d = new int[11];
		for(int i=0;i<T;i++) {
			int n = Integer.parseInt(br.readLine());
			
			//d[n] = d[n-2]+d[n-1]+d[n]
			d[1]=1;
			d[2]=2;
			d[3]=4;
			for(int j=4;j<=n;j++) {
				d[j] = d[j-1]+d[j-2]+d[j-3];
			}
			System.out.println(d[n]);
		}
	}
}

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준][1074]Z  (0) 2021.08.17
[백준]선물 전달  (0) 2021.08.16
[백준]설탕배달  (0) 2021.08.14
[백준]개미  (0) 2021.08.08
[백준]경비원  (0) 2021.08.07

/* 문제설명 */

상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그램 봉지와 5킬로그램 봉지가 있다.

상근이는 귀찮기 때문에, 최대한 적은 봉지를 들고 가려고 한다. 예를 들어, 18킬로그램 설탕을 배달해야 할 때, 3킬로그램 봉지 6개를 가져가도 되지만, 5킬로그램 3개와 3킬로그램 1개를 배달하면, 더 적은 개수의 봉지를 배달할 수 있다.

상근이가 설탕을 정확하게 N킬로그램 배달해야 할 때, 봉지 몇 개를 가져가면 되는지 그 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. (3 ≤ N ≤ 5000)

출력

상근이가 배달하는 봉지의 최소 개수를 출력한다. 만약, 정확하게 N킬로그램을 만들 수 없다면 -1을 출력한다.

 

 

 

 


 

 

 

/* 풀이방법 */

동적계획법 기법중 메모이제이션 기법을 사용했다.

처음에 N크기만한 배열을 생성하고 -1로 초기화 했다.

그리고 설탕의 최소 크기인 3과 5 를 1로 초기화 한다 --->이때 배열의 범위에 유의해라!

그리고 그 이후 목적지(d[N])까지 반복문을 통해 이동하는데, 

이때 d[i-3]이나 d[i-5]가 -1이 아니라면 해당 위치 +1이 가장 최소값이 된다.

왜냐하면, d[i-3]에는 i-3까지 도착하는 최소값이 기록되어 있으므로 거기에 설탕 3kg하나 더하는 것이다.

d[i-3]과 d[i-5], 둘 다 -1이라면 당연히 현재위치도 -1이 된다.

이러한 방식으로 동적계획법을 구현했다.

 


 

/* 해답코드 */

package baekjoon;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

//설탕배달
//dp의 기본
public class b2839 {
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(br.readLine());
		int[] d = new int[N+1];
		for(int i=0;i<=N;i++) {
			d[i]=-1;
		}
		if(N>=3)
			d[3] = 1;
		if(N>=5)
			d[5] = 1;
		for(int i=6;i<=N;i++) {
			if(d[i-3]==-1&&d[i-5]==-1)
				continue;
			else if(d[i-3]==-1)
				d[i]=d[i-5]+1;
			else if(d[i-5]==-1)
				d[i]=d[i-3]+1;
			else
				d[i]=Math.min(d[i-3]+1, d[i-5]+1);
		}
		System.out.println(d[N]);
	}

}

 

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준]선물 전달  (0) 2021.08.16
[백준]1,2,3 더하기  (0) 2021.08.14
[백준]개미  (0) 2021.08.08
[백준]경비원  (0) 2021.08.07
[백준]색종이  (0) 2021.08.07

/* 문제설명 */

가로 길이가 w이고 세로 길이가 h인 2차원 격자 공간이 있다. 이 격자는 아래 그림처럼 왼쪽 아래가 (0,0)이고 오른쪽 위가 (w,h)이다. 이 공간 안의 좌표 (p,q)에 개미 한 마리가 놓여있다. 개미는 오른쪽 위 45도 방향으로 일정한 속력으로 움직이기 시작한다. 처음에 (p,q)에서 출발한 개미는 1시간 후에는 (p+1,q+1)로 옮겨간다. 단, 이 속력으로 움직이다가 경계면에 부딪치면 같은 속력으로 반사되어 움직인다.

위 그림은 6×4 격자에서 처음에 (4,1)에서 출발한 개미가 움직인 길을 보여주고 있다. 처음에 (4,1)에 있는 개미는 2시간 후에 (6,3)에 있으며 8시간 후에 (0,1)에 있다. 만일 그 개미가 처음에 (5,3)에 있었다면 매 시간마다 (6,4), (5,3), (4,2), (3,1)로 움직인다. 

여러분은 크기 w×h인 격자 공간에서 처음에 (p,q)에서 출발하는 개미의 t시간 후의 위치 (x,y)를 계산하여 출력해야 한다. 개미는 절대 지치지 않고 같은 속력으로 이동한다고 가정한다. 

문제에서 w와 h는 자연수이며 범위는 2 ≤ w,h ≤ 40,000이다. 그리고 개미의 초기 위치 p와 q도 자연수이며 범위는 각각 0 < p < w과 0 < q < h이다. 그리고 계산할 시간 t의 범위는 1 ≤ t ≤ 200,000,000이다.

입력

첫줄에는 w와 h가 공백을 사이에 두고 주어진다. 그 다음 줄에는 초기 위치의 좌표값 p와 q가 공백을 사이에 두고 주어진다. 3번째 줄에는 개미가 움직일 시간 t가 주어진다. 

출력

출력은 t 시간 후에 개미의 위치 좌표 (x,y)의 값 x와 y를 공백을 사이에 두고 출력한다. 

 

 

 

 


 

 

 

/* 풀이방법 */

 

대각선으로 움직이는 것은 결국 가로한칸, 세로한칸을 동시에 움직이는 것과 같다!

그리고 높이나 너비로 나누었을때 해당 숫자가 짝수이면 0부터 시작, 홀수이면 벽에서부터 시작한다.

이점을 고려해서 반복문없이 푸는데 성공했으나,

StringBuilder를 사용하지 않아 계속 시간초과가 나서 매우 괴로웠다 ㅠ

(다음 스터디에서는 StringBuilder에 대해 더 공부해봐야겠다.)

                         


 

/* 해답코드 */

package baekjoon;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

//개미
public class b10158 {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		int W = Integer.parseInt(st.nextToken());
		int H = Integer.parseInt(st.nextToken());
		
		st = new StringTokenizer(br.readLine());
		int x = Integer.parseInt(st.nextToken());
		int y = Integer.parseInt(st.nextToken());
		int T = Integer.parseInt(br.readLine());
		
		//짝수면 0에서 출발, 홀수면 벽에서 출발
		boolean moveX = (x+T)/W%2==0;
		boolean moveY = (y+T)/H%2==0;
		
		x=(x+T)%W;
		if(!moveX) {
			x=W-x;
		}
		
		y=(y+T)%H;
		if(!moveY) {
			y=H-y;
		}
		StringBuilder sb = new StringBuilder();
		sb.append(x);sb.append(" ");sb.append(y);
		bw.write(sb.toString());
		bw.flush();
		bw.close();
	}

}

'Coding Test > Baekjoon' 카테고리의 다른 글

[백준]1,2,3 더하기  (0) 2021.08.14
[백준]설탕배달  (0) 2021.08.14
[백준]경비원  (0) 2021.08.07
[백준]색종이  (0) 2021.08.07
[백준]수열  (0) 2021.08.07

+ Recent posts