이 문제는 DP로 푼 사람들이 많다. 그런데 나는 이분탐색이 떠올라서 이분탐색으로 풀었다. 혹시나 나처럼 이분탐색으로 접근한 사람이 있다면 참고가 되길 바라며 작성한다.
왜 이분탐색이라고 생각했는가?
1. 처음에는 길이와 용량의 범위가 크다고 생각했다.
(지금 보니 별로 안크긴 함. 2^23 = 8,388,608. 다음에는 계산을 잘 해야겠다)
2. mid 값과 부분조합을 잘 섞으면 될 것 같았다.
public class Main {
static long D;
static int P;
static long[][] pipes;
static boolean[] visit;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
D = sc.nextLong();
P = sc.nextInt();
pipes = new long[P][2];
visit = new boolean[P];
for(int i = 0; i < P; i++) {
pipes[i][0] = sc.nextLong(); //길이
pipes[i][1] = sc.nextLong(); //용량
}
Arrays.sort(pipes, (a, b) -> a[1]!=b[1] ? Long.compare(a[1], b[1]) : Long.compare(a[0], b[0]));
long left = 1;
long right = pipes[P-1][1];
long answer = 1;
while(left <= right) {
long mid = (left+right)/2;
boolean making = false;
int start = 0;
for(int i = 0; i < P; i++) {
if(pipes[i][1] >= mid) {
start = i;
int size = P-start; // 부분집합 크기
making = subset(size, 0, 0, start, new long[size]);
break;
}
}
if(making) {
left = mid + 1;
answer = mid;
} else {
right = mid - 1;
}
}
System.out.print(answer);
sc.close();
}
private static boolean subset(int m, int cnt, long sum, int i, long[] path) {
if(cnt == m || i == P || sum >= D) {
if(sum == D) {
return true;
}
return false;
}
if(subset(m, cnt, sum, i+1, path)) return true;
path[cnt] = pipes[i][0];
if(subset(m, cnt+1, sum+pipes[i][0], i+1, path)) return true;
path[cnt] = 0;
return false;
}
}