다리 놓기 성공
0.5 초 (추가 시간 없음) | 128 MB | 64625 | 29963 | 24502 | 48.438% |
문제
재원이는 한 도시의 시장이 되었다. 이 도시에는 도시를 동쪽과 서쪽으로 나누는 큰 일직선 모양의 강이 흐르고 있다. 하지만 재원이는 다리가 없어서 시민들이 강을 건너는데 큰 불편을 겪고 있음을 알고 다리를 짓기로 결심하였다. 강 주변에서 다리를 짓기에 적합한 곳을 사이트라고 한다. 재원이는 강 주변을 면밀히 조사해 본 결과 강의 서쪽에는 N개의 사이트가 있고 동쪽에는 M개의 사이트가 있다는 것을 알았다. (N ≤ M)
재원이는 서쪽의 사이트와 동쪽의 사이트를 다리로 연결하려고 한다. (이때 한 사이트에는 최대 한 개의 다리만 연결될 수 있다.) 재원이는 다리를 최대한 많이 지으려고 하기 때문에 서쪽의 사이트 개수만큼 (N개) 다리를 지으려고 한다. 다리끼리는 서로 겹쳐질 수 없다고 할 때 다리를 지을 수 있는 경우의 수를 구하는 프로그램을 작성하라.
입력
입력의 첫 줄에는 테스트 케이스의 개수 T가 주어진다. 그 다음 줄부터 각각의 테스트케이스에 대해 강의 서쪽과 동쪽에 있는 사이트의 개수 정수 N, M (0 < N ≤ M < 30)이 주어진다.
출력
각 테스트 케이스에 대해 주어진 조건하에 다리를 지을 수 있는 경우의 수를 출력한다.
예제 입력 1 복사
3
2 2
1 5
13 29
예제 출력 1 복사
1
5
67863915
풀이
//서쪽에 있는 다리가 동쪽에 있는 다리를 선택하는 느낌이다.
//서쪽에 하나의 다리가 동쪽에 어떤 다리를 골랐을 경우 선택된 다리 이후의 것만을 고려해야한다.
//이것은 조합의 진행 방식과 같다. 반복문의 시작인덱스를 매개변수로 전달해주고, 전달할때 +1 해주니까
//서쪽다리를 기준으로 동쪽의 다리를 뽑고, 한뽑고를 진행하면 된다. 조합의 진행순서상 다리가 엇갈리는 경우는 나오지않는다.
라는 생각으로 조합으로 풀이를 해보았다.
하지만 시간초과가 발생
해당 코드는 아래와 같다.
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
//서쪽에 있는 다리가 동쪽에 있는 다리를 선택하는 느낌이다.
//서쪽에 하나의 다리가 동쪽에 어떤 다리를 골랐을 경우 선택된 다리 이후의 것만을 고려해야한다.
//이것은 조합의 진행 방식과 같다. 반복문의 시작인덱스를 매개변수로 전달해주고, 전달할때 +1 해주니까
//서쪽다리를 기준으로 동쪽의 다리를 뽑고, 한뽑고를 진행하면 된다. 조합의 진행순서상 다리가 엇갈리는 경우는 나오지않는다.
static int count;
static boolean[] visited;
public static void main(String[] args) throws IOException {
int n = Integer.parseInt(br.readLine());
for (int i = 0; i < n; i++) {
String[] input = br.readLine().split(" ");
int westBridges = Integer.parseInt(input[0]);
int eastBridges = Integer.parseInt(input[1]);
visited = new boolean[eastBridges];
combination(eastBridges, westBridges, 0);
bw.write(count + "\n");
count = 0;
}
bw.flush();
bw.close();
}
public static void combination(int n, int r, int start) {
if (r == 0) {
count++;
return;
}
for (int i = start; i < n; i++) {
if (!visited[i]) {
visited[i] = true;
combination(n, r - 1, i + 1);
visited[i] = false;
}
}
}
}
시간초과가 난이유는?
일단 시간제한은 0.5초이고
테스트케이스는 몇개가 나올지 모른다.
다리의 최대갯수는 30개라고 한다.
조합의 시간복잡도는 O(2^N) 이므로
2의 30승 1,073,741,824 약 10억 , 다리가 30개일경우 조합계산에만 약 10초가 걸린다.
여기서 시간초과가 발생하였다.
그렇다면 어떻게 해야 조합을 할때 시간이 별로 안걸릴까
해답 : 파스칼 삼각형
nCr = n-1Cr + n-1Cr-1 이기 때문에 해당 식을 이용하여 풀이한다.
30C5= 29C5 + 29C4 이고 29C5 는 28C5 + 28C4이기 떄문에
큰 문제를 작은문제로 나눠서 풀이하는 다이나믹 프로그래밍을 이용한다.
작은문제들을 dp배열에 저장해서(메모이제이션) 큰문제를 해결해보자.
바텀업, 탑다운 둘다 사용해보자.
바텀업
import java.io.*;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static int count;
static int[][] paskalTriangle;
public static void main(String[] args) throws IOException {
int n = Integer.parseInt(br.readLine());
for (int i = 0; i < n; i++) {
String[] input = br.readLine().split(" ");
int westBridges = Integer.parseInt(input[0]);
int eastBridges = Integer.parseInt(input[1]);
paskalTriangle = new int[eastBridges+1][eastBridges+1];
combination(eastBridges, westBridges);
bw.write(paskalTriangle[eastBridges][westBridges]+"\n");
}
bw.flush();
bw.close();
}
public static void combination(int n,int r) {
//바텀업으로 파스칼삼각형 각각의 값을 채운다.
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= r; j++) {
if (i == j || j == 0) {
paskalTriangle[i][j] = 1;
} else{
paskalTriangle[i][j] = paskalTriangle[i - 1][j] + paskalTriangle[i - 1][j - 1];
}
}
}
}
}
통과
탑다운
import java.io.*;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static int count;
static int[][] paskalTriangle;
public static void main(String[] args) throws IOException {
int n = Integer.parseInt(br.readLine());
for (int i = 0; i < n; i++) {
String[] input = br.readLine().split(" ");
int westBridges = Integer.parseInt(input[0]);
int eastBridges = Integer.parseInt(input[1]);
paskalTriangle = new int[eastBridges+1][eastBridges+1];
combination(eastBridges, westBridges);
bw.write(paskalTriangle[eastBridges][westBridges]+"\n");
}
bw.flush();
bw.close();
}
public static int combination(int n,int r) {
//탑다운 방식 원하는값을 얻기위해 맨 아래 기저값까지 내려갔다가 dp배열을 채우면서 올라오고 결국 원하는 값을 얻는 방식
if (n == r || r == 0) { //n과 r이 같거나 r이 0이라면 경우의 수는 1이므로
paskalTriangle[n][r] = 1; //파스칼삼각형의 해당 위치는 1로 채우고
return paskalTriangle[n][r]; //그 값을 리턴해준다.
}
else{ //아니라면
if (paskalTriangle[n][r] == 0) { //삼각형 해당위치의 값이 비어있다면
paskalTriangle[n][r] = combination(n - 1, r) + combination(n - 1, r - 1); // 재귀를 이용하여 채워준다.
}
return paskalTriangle[n][r]; // 방금 위에서 채워줬거나 , 아니면 원래 채워져있었다면 그 값을 리턴한다.
}
}
}
'자바 > 알고리즘 문제 풀이' 카테고리의 다른 글
백준/1676 팩토리얼 0의 개수 // BigInteger , 0의개수 규칙 (0) | 2022.12.15 |
---|---|
백준/9375 패션왕 신해빈 // 조합 , 경우의 수 (0) | 2022.12.15 |
★백준/11051 이항 계수 2 /조합,BigInteger,파스칼의 삼각형 (0) | 2022.12.14 |
백준/11050 이항 계수 1 // 조합 -> (dfs + 백트래킹) or 재귀 (0) | 2022.12.14 |
백준/2609 최대공약수와 최대공배수 // 유클리드 호제법 (0) | 2022.12.14 |
댓글