BOJ 16987: 계란으로 계란치기 https://www.acmicpc.net/problem/16987
내구도(dura)
와 무게(weight)
가 있다.내구도(dura)
는 다른 계란의 무게(weight)
만큼 깎인다.내구도(dura)
가 0 이하
가 되면 깨진다.랜덤으로 선택
한다.손에 든 계란이 깨져있
거나 다른 계란들 전부가 깨져있다
면 아무일도 하지 않고 넘어간다.최대한 많은 계란을 깨도록
한다.import java.util.*;
import java.io.*;
public class Main {
static int N;
static int[] dura;
static int[] weight;
static int max = Integer.MIN_VALUE;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
N = Integer.parseInt(br.readLine());
dura = new int[N];
weight = new int[N];
for(int i=0; i<N; i++) {
st = new StringTokenizer(br.readLine(), " ");
dura[i] = Integer.parseInt(st.nextToken()); // 계란의 내구도
weight[i] = Integer.parseInt(st.nextToken()); // 계란의 무게
}
bt(0, 0); // 0번째 계란부터 시작 , 이 땐 깨진 계란 0개
System.out.println(max);
}
static void bt(int idx, int cnt) {
// 마지막 계란까지 다 들어봤으면 종료
if(idx == N) {
// 최댓값 갱신
max = Math.max(max, cnt);
return;
}
// 손으로 든 계란이 이미 깨졌거나 모든 계란이 이미 다 깨져 있다면
if(dura[idx] <= 0 || cnt == N-1) {
// 다음 계란을 들어 봄
bt(idx + 1, cnt);
return;
}
// 다른 계란들과 모두 부딪혀봄
int nCnt = cnt;
for(int i=0; i<N; i++) {
// 손으로 들고 있는 계란과 부딪히려고 하는 계란이 같은 계란이라면 통과
if(i == idx) continue;
// 부딪혀 보려고 하는 계란이 이미 깨져있다면 통과
if(dura[i] <= 0) continue;
// 계란끼리 부딪혀봄 (현재 손에 들고 있는 계란의 인덱스, 부딪혀보려는 타겟 계란 인덱스)
hitEgg(idx, i);
// 부딪혀 봤는데 손에 든 계란이 깨지면 cnt++
if(dura[idx] <= 0) {
cnt++;
}
// 부딪혀 봤는데 타겟이 된 계란이 깨지면 cnt++
if(dura[i] <= 0) {
cnt++;
}
// 재귀 호출 -> 다음 계란 들어 봄
bt(idx + 1, cnt);
// for문의 다음 i를 위해 값을 원상복구 해 줌
recoveryEgg(idx, i);
cnt = nCnt;
}
}
// 계란끼리 부딪혀보는 메소드
static void hitEgg(int handEgg, int targetEgg) {
dura[targetEgg] -= weight[handEgg];
dura[handEgg] -= weight[targetEgg];
}
// 다시 원상복구 하는 메소드
static void recoveryEgg(int handEgg, int targetEgg) {
dura[targetEgg] += weight[handEgg];
dura[handEgg] += weight[targetEgg];
}
}
다른 백트래킹 문제
에선 가능한 조합을 모두 만들어 놓고
종료 조건 안에서 마무리 연산을 해주는 경우가 많았다.이번 문제
에선 종료조건이 아닌 재귀호출을 하기위한 for문 안에서 연산을 하여 해결
하는 문제였다.유망한 조건
만 추려서 재귀 호출을 사용하는 문제였다.