[Silver I] 물약 구매 - 24954>
성능 요약
메모리: 294016 KB, 시간: 708 ms
주어진 몰약을 모두 구매할 때 구매하는 순서를 고려하여 물약을 가장 싸게 샀을때 그 비용을 출력하는 문제
⭕ 접근 방법. 백트래킹
1. 구매한 물약을 i, 할인 받을 물약을 j 로 하는 2차원 배열 sale[i][j] 를 만들어 할인받을 금액을 담늗다.
2. 재귀함수를 이용하여 depth 번째에 구매할 물약을 선택한다.
➡️ 해당 풀이법의 시간 복잡도 :
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main_24954 {
static int N; // 물약의 종류 수
static int price[]; // 각 물약의 가격
static int sale[][]; // 각 물약을 구매할 때 할인되는 정보
static int minCost = Integer.MAX_VALUE; // 물약을 가장 싸게 살 때 필요한 최소 비용
static boolean visited[]; // 물약을 방문했는지 여부를 저장하는 배열
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine()); // 물약의 종류 수 입력
price = new int[N+1]; // 물약의 가격을 저장할 배열 초기화
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 1; i < N+1; i++) {
price[i] = Integer.parseInt(st.nextToken()); // 각 물약의 가격 입력
}
sale = new int[N+1][N+1]; // 물약 할인 정보를 저장할 배열 초기화
for (int i = 1; i < N+1; i++) {
int p = Integer.parseInt(br.readLine()); // 물약 할인 정보의 개수 입력
for (int j = 0; j < p; j++) {
st = new StringTokenizer(br.readLine());
int saleIdx = Integer.parseInt(st.nextToken());
int salePrice = Integer.parseInt(st.nextToken());
sale[i][saleIdx] = salePrice; // 물약을 구매하면 할인되는 정보 입력
}
}
visited = new boolean[N+1]; // 방문 여부를 저장하는 배열 초기화
findMinCost(0, 0); // 가장 싸게 물약을 살 때 필요한 최소 비용을 찾는 메서드 호출
System.out.println(minCost); // 최소 비용 출력
}
// 물약을 가장 싸게 살 때 필요한 최소 비용을 찾는 메서드
private static void findMinCost(int depth, int cost) {
if(cost >= minCost) return; // 현재 비용이 최소 비용을 초과하면 종료
if(depth == N){ // 모든 물약을 구매한 경우
minCost = Math.min(minCost, cost); // 현재 비용과 최소 비용을 비교하여 더 작은 값을 최소 비용으로 갱신
return;
}
for (int i = 1; i < N+1; i++) { // 모든 물약에 대해 반복
if(visited[i]) continue; // 이미 방문한 물약이면 다음 물약으로 넘어감
visited[i] = true; // 현재 물약을 방문했음을 표시
int originPrice[] = Arrays.copyOf(price, N+1); // 물약을 구매하기 전의 가격을 저장
for (int j = 1; j < N+1; j++) { // 해당 물약을 구매하고 나서 할인되는 물약들에 대해 반복
if(price[j] - sale[i][j] <=0 ){ // 할인되는 가격이 물약의 가격보다 크면
price[j] = 1; // 가격을 1로 설정 (가격은 0 이하는 되지 않음)
} else { // 그렇지 않으면
price[j] -= sale[i][j]; // 할인된 가격으로 업데이트
}
}
findMinCost(depth+1, cost+price[i]); // 다음 물약을 선택하고 재귀적으로 호출
price = Arrays.copyOf(originPrice, N+1); // 물약을 구매하기 전의 가격으로 되돌림
visited[i] = false; // 현재 물약 방문 표시 해제
}
}
}