총 10분 중 11분
2001
시즌 2개, 그리고 영화
시즌 2:
5화
“아일랜드”
출연: 이나영, 김민준, 김민정, 현빈
장르: 애초에 역경을 딛고 이룩하는 숭고한 사랑이란 없다. 그 역경 자체가 사랑이다.
프로그램 특징: 그 곳에서 살아남는 사랑이 어떤 모습으로 걸어오는지 기다려 보고 싶다.
장르: 애초에 역경을 딛고 이룩하는 숭고한 사랑이란 없다. 그 역경 자체가 사랑이다.
프로그램 특징: 그 곳에서 살아남는 사랑이 어떤 모습으로 걸어오는지 기다려 보고 싶다.
회차
-
[JAVA][BOJ 2098] 외판원 순회와 비트 연산0521분문제링크문제 파악TSP(Traveling Salesman Problem) 가중치가 있는 단방향 그래프를 가장 작은 비용을 들이면서 순회하는 경로를 구해라!첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 16) 다음 N개의 줄에는 비용 행렬이 주어진다. 각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다. W[i][j]는 도시 i에서 j로 가기 위한 비용을 나타낸다. 도시 i에서 j로 이동할 수 없는 경우에는 W[i][j]=0이라고 한다항상 순회할 수 있는 경우만 입력으로 주어진다.접근 방법DP[현재도시][현재까지 방문한 도시 리스트] = 남은 모든 도시를 경유하는 데 드는 최소 비용남은 도시를 경유하는 데 드는 최소 비용은 DFS로 구현리스트를 변수 1개에 ..
-
[JAVA][BOJ 1256] 조합: 사전 찾기0515분문제링크문제 파악N개의 'a', M개의 'z'로 사전을 만들었다. 알파벳 순서로 수록된 사전에서 K번째 문자열 구하기사전에 있는 수가 K보다 작으면 -1 반환N개의 'a', M개의 'z', K번째 문자열1 ≤ N, M ≤ 1001 ≤ K ≤ 1,000,000,000접근 방법각 자리 수까지 만들 수 있는 문자열 개수 중복한 문자를 가지기 때문에 만들 수 있는 문자열의 개수는 N+M개 중 N개 또는 M개를 택하는 것과 같다.순열과 똑같이 전체 중에서 칸막이를 넣는다고 생각하면 된다.그리고 순열의 nCr = n-1 C r-1 + n-1 C r 을 이용하면 DP가 된다. DP부문 문제가 해결된 상황에서 마지막 데이터의 선택 여부에 따른 경우의 수 계산하는 것이다.DP[5][3] = DP[4][2] + DP[..
-
[백준 12865][dp] 배낭: knapsack0630분드디어 기대하고 기대하던 배낭문제다. 이 문제를 만나고 나서야 DP의 의미를 이해할 수 있게 되었다. DP는 a, b, c, d가 있을 때 abc, abd, acd ... 이런 조합을 만드는 문제가 아니었다.a를 넣었을 때와 넣지 않았을 때 두 개로 나뉜 경우에 대해 각각이 b를 넣었을 때와 넣지 않았을 때로 나누는 방식으로 풀었어야 했다. 헐랭~ https://youtu.be/rhda6lR5kyQ?si=wVKtxIhe4A9wsj81DP는 초깃값 설정이 중요하다. 우리가 구하고자 하는 값은 가치의 최댓값이고, 입력값은 항목의 개수와 각 항목당 무게와 가치가 주어진다. dp의 data는 value 의 sum이다. 가질 수 있는 value의 최대값을 구하는 문제이므로 n 번째 항목까지의 value sum을 ..
-
[프로그래머스][dp] 땅따먹기0626분프로그래머스 알고리즘 강좌가 dp 이해에 도움이 됐다는 글을 보고 '땅따먹기'를 시도했다. 직접 짜보고 dp 코드와 비교하니까 dp의 느낌이 확 와닿는다. dp는 모든 경우의 수를 확인하는데, 각 요소가 있고, 없고에 따라 경우를 만든다. 문제와 함께 보자 문제ㅎ. 하지만 나는 어제 dp를 정리해 놓고도 전혀 떠오르지 않아서 풀리는 대로 풀었다. (이해가 덜 됐다ㅜ)내 풀이 방법1. 현재 index(j)를 이전 max의 index와 비교해 같지 않은 경우에만 들어간다. - if ( i == 0 ) 인 예외를 주는 데 시간이 오래 걸렸다. 다시 생각해 보니 첫 열은 index가 뭐든 관계없으니까 preindex 처음 선언할 때 preindex = -1; 했으면 됐겠다. 2. index가 같지 않은 경우..
-
[백준 1106] DP 동적프로그래밍0625분동적 프로그래밍(Dynamic programming)이란 과거에 사용한 값을 중복해서 사용하는 경우에서 사용할 알고리즘을 말한다. 대표적으로 배낭 문제, 피보나치 수열이 있다. 이전에 구해놓은 값을 재사용하기 때문에 재귀함수를 이용해야 한다. 재귀함수를 naive하게 사용하게 되면 시간, 공간복잡도가 폭발적으로 증가한다.부분 문제에 대한 값을 미리 계산해놓고 한 번에 이용하는 것이 시공간 관점에서 효율적이다. 따라서 Memoization(메모이제이션)을 활용한다.같은 문제의 풀이를 재활용하는 방식인데, 재귀의 방법이 있다. 부분 문제에 대한 경우의 수를 모두 구할 건데, 이 때 재귀를 사용한다. 부분 문제를 넣고(1), 빼고(0) 에 대한 경우의 수를 구하는 것이다.dp의 memoization은 하향식으..
Algorithm/Dynamic Programming
[JAVA][BOJ 2098] 외판원 순회와 비트 연산
728x90
반응형
문제링크
문제 파악
TSP(Traveling Salesman Problem) 가중치가 있는 단방향 그래프를 가장 작은 비용을 들이면서 순회하는 경로를 구해라!
첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 16) 다음 N개의 줄에는 비용 행렬이 주어진다. 각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다. W[i][j]는 도시 i에서 j로 가기 위한 비용을 나타낸다.
- 도시 i에서 j로 이동할 수 없는 경우에는 W[i][j]=0이라고 한다
항상 순회할 수 있는 경우만 입력으로 주어진다.
접근 방법
DP[현재도시][현재까지 방문한 도시 리스트] = 남은 모든 도시를 경유하는 데 드는 최소 비용
- 남은 도시를 경유하는 데 드는 최소 비용은 DFS로 구현
리스트를 변수 1개에 저장하기 위해 이진수로 표현해 비트연산한다.
도시 | 방문 여부 | 비트 위치 |
0번 도시 | 1이면 방문 | 0001 (1) |
1번 도시 | 1이면 방문 | 0010 (2) |
2번 도시 | 1이면 방문 | 0100 (4) |
3번 도시 | 1이면 방문 | 1000 (8) |
예를 들어 3번, 0번 방문시 1001 -> 9 로 표현한다.
비트 연산
그동안 피해왔던 비트 연산...
기호 | 기능 | 예 | 연산값 |
& | AND (A, B 모두 1이어야 1) | (1 & 1 ) | 1 |
| | OR (A, B 둘 중 하나라도 1이면 1) | (1 | 0) | 1 |
<< | A를 왼쪽으로 B만큼 비트 이동 | (1 << 2) | 0001 0010 ----- 0100 = 4 |
>> | A를 오른쪽으로 B만큼 비트 이동 | (8 >> 2) | 1000 0010 ---- 0010 = 2 |
DP[c][v] = Math.min(DP[c][v], DP[i][v | (1<<i)] + W[c][i])
- [v | (1 << i) ]
i번째 도시를 방문했다는 사실을 저장한다.- 여기서 v가 누적값인데 비트 연산이면 0, 1을 반환하는게 누적값으로 반영이 안되지 않나? 헷갈렸다.
v가 0101이고, 1번 도시를 방문하려면 [0101 | 0010]이고, 각 자리수마다 OR 연산을 통해 0111로 바뀐다.
때문에 0, 1, 2 방문했다는 처리가 가능해진다.
- 여기서 v가 누적값인데 비트 연산이면 0, 1을 반환하는게 누적값으로 반영이 안되지 않나? 헷갈렸다.
- if ( ( v & (1 << i)) == 0 )
i번째 도시 방문했다면 (1 & 1) 이므로 1이 나오지만, 방문하지 않았다면 0을 반환한다. - if (v == (1 << N) -1)
N만큼 왼쪽으로 비트 이동했으니, 10000(16)인데 -1해서 15면 01111로 모든 도시를 방문했다는 상태를 확인할 수 있다. - W[c][i] 는 도시 c에서 i로 이동하는 비용
w[i][j] i -> j 도시로 이동하는 비용 저장 배열
dp[c][v] 현재 도시 c, 현재까지 방문한 모든 도시 리스트 v
앞으로 남은 모든 도시를 방문할 때 드는 최소 비용
for(i -> 0-N)
for (j -> 0 - 1<<N)
DP를 Integer.MAX_VALUE로 초기화
tsp(c,v) 모든 경우의 수 완전 탐색
tsp(c,v)
if (모든 도시 방문)
시작 도시로 돌아갈 수 있다면 return w[c][시작도시]
없다면 return MAX_VALUE
if (이미 계산한 적이 있다면) return dp[c][v]
for(i -> 0-N)
if (방문한 적 없고 갈 수 있는 도시일 때)
dp[c][v] = Math.min(dp[c][v], tsp(i, (v|(1<<i))) + w[c][i])
return dp[c][v]
코드 구현
import java.io.*;
import java.util.*;
public class Main {
static final int INF = 1_000_000_000;
static int N;
static int[][] W;
static int[][] DP;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
W = new int[N][N];
DP = new int[N][1 << N];
for (int[] row : DP) Arrays.fill(row, -1);
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
W[i][j] = Integer.parseInt(st.nextToken());
}
}
System.out.println(tsp(0, 1)); // 시작: 도시 0, 방문 상태: 000...0001
}
static int tsp(int cur, int visited) {
if (visited == (1 << N) - 1) {
return W[cur][0] == 0 ? INF : W[cur][0]; // 모든 도시 방문 후 출발 도시로 복귀
}
if (DP[cur][visited] != -1) return DP[cur][visited];
int min = INF;
for (int next = 0; next < N; next++) {
if ((visited & (1 << next)) == 0 && W[cur][next] != 0) {
int cost = tsp(next, visited | (1 << next)) + W[cur][next];
min = Math.min(min, cost);
}
}
return DP[cur][visited] = min;
}
}
배우게 된 점
1. 비트연산자로 방문 경로 리스트를 변수 1개로 표현하는 방법을 알았따.
2. DP의 초기값을 -1이나 INF나 설정해놓고 검사해야 정확한 체크가 가능하다. 0 을 기준으로 검사하면 계산하지 않은 상태를 구분할 수 없기 때문에 오류가 날 수 있다.
질문
728x90
'Algorithm > Dynamic Programming' 카테고리의 다른 글
[JAVA][BOJ 1256] 조합: 사전 찾기 (2) | 2025.05.15 |
---|---|
[백준 12865][dp] 배낭: knapsack (2) | 2024.06.30 |
[프로그래머스][dp] 땅따먹기 (2) | 2024.06.26 |
[백준 1106] DP 동적프로그래밍 (2) | 2024.06.25 |
2025:05:21
Algorithm/Dynamic Programming
[JAVA][BOJ 2098] 외판원 순회와 비트 연산