인프런 커뮤니티 질문&답변

kje010907님의 프로필 이미지

작성한 질문수

세계 대회 진출자가 알려주는 코딩테스트 A to Z (with Python)

파라매트릭 서치 알고리즘 [문제풀이] : BOJ 2110

2110번 문제 ispossible 함수 내부에서 조건문이 궁금합니다

해결된 질문

24.09.14 17:36 작성

·

32

0

안녕하세요 파라매트릭 서치 2110 풀다가 오답처리된 코드에 궁금한 점 생겨 질문드립니다.

 

  • 정답처리된 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class P2110 {
    static int N, C;
    static long result;
    static int[] home;
    static long parametricSearch() {
        long left=0;
        long right=home[N-1]-home[0];
        long mid = (left+right)/2;
        while(left<=right) {
            if(isPossible(mid)) {
                left = mid+1;
                result = mid;
            } else {
                right = mid-1;
            }
            mid = (left+right)/2;
        }
        return result;
    }
    static boolean isPossible(long mid) {
        //그리디한판단 : 맨 첫번째를 두는게 이득 + 거리 mid만큼 떨어진 바로 다음 집에 두는게 이득
        int cnt=1;
        int lastIdx=0;
        for (int i = 1; i < N ; i++) {
            if(home[i]-home[lastIdx]>=mid) {
                lastIdx=i;
                cnt++;
            }
        }
        return C<=cnt;
    }
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());

        home = new int[N];
        for (int i = 0; i < N; i++) home[i] = Integer.parseInt(br.readLine());

        Arrays.sort(home);
        System.out.println(parametricSearch());
    }
}

 

  • 75%에서 오답처리된 코드

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class P2110 {
    static int N, C;
    static long result;
    static int[] home;
    static long parametricSearch() {
        long left=0;
        long right=home[N-1]-home[0];
        long mid = (left+right)/2;
        while(left<=right) {
            if(isPossible(mid)) {
                left = mid+1;
                result = mid;
            } else {
                right = mid-1;
            }
            mid = (left+right)/2;
        }
        return result;
    }
    static boolean isPossible(long mid) {
        //그리디한판단 : 맨 첫번째를 두는게 이득 + 거리 mid만큼 떨어진 바로 다음 집에 두는게 이득
        int cnt=1;
        int lastIdx=0;
        for (int i = 1; i < N ; i++) {
            if(home[i]-home[lastIdx]>=mid) {
                lastIdx=i;
                cnt++;
            }
            if(cnt==C) return true;
        }
        return false;
    }
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());

        home = new int[N];
        for (int i = 0; i < N; i++) home[i] = Integer.parseInt(br.readLine());

        Arrays.sort(home);
        System.out.println(parametricSearch());
    }
}

 

다른 부분은 전부 동일하고

최소거리가 mid일 때 공유기 C개를 두는 것이 가능한지 판별하는 isPossible 내부에서 return만 다릅니다.

for (int i = 1; i < N ; i++) {
    if(home[i]-home[lastIdx]>=mid) {
        lastIdx=i;
        cnt++;
    }
    if(cnt==C) return true;
}
return false;

설치할때마다 cnt를 증가시키고, cnt==C가 되는 시점에 도달하면 어차피 현재의 mid로 공유기 C개를 두는게 가능하단 의미니까 true를 리턴해서 끝내고, cnt==C에 도달하지 못한다면 C보다 적은 개수만 설치할 수 있으니 false를 리턴한다고 작성했습니다.

반면에 강의안으로 제공해주신 코드에서는 반복문 안에서 판단해서 리턴하는 것이 아니라, 반복문 전부 돈 결과인 cnt와 C를 비교해서 리턴하는 것으로 이해했습니다.

 

정답풀이가 맞는 방식이라는 점은 이해가 가는데 오답풀이가 어떤 반례가 있는지는 잘 모르겠습니다

답변 2

0

알리 Ally님의 프로필 이미지
알리 Ally
지식공유자

2024. 09. 17. 12:03

안녕하세요. kje010907님!

공유해주신 코드 모두 채점 결과 정답처리 되는걸로 확인됐습니다.

 

질문에 남겨주신 말씀대로 두 코드의 차이점은 isPossble 부분인데,

그 중에서도 if(cnt==C) return true;return C<=cnt;의 차이라 볼 수 있습니다.

여기서 cnt==C에 도달하지 못한다면 C보다 적은 개수만 설치할 수 있으니 false를 리턴한다는 점에서 두 코드의 논리는 동일하다고 볼 수 있습니다.

 

다시 한 번 채점해보시고, 여전히 오답으로 뜨거나 궁금하신점 있으시면 추가 질문 남겨주세요.

감사합니다. :)

0

인프런 AI 인턴님의 프로필 이미지

2024. 09. 14. 17:41

안녕하세요, 인프런 AI 인턴입니다.

kje010907님께서 언급하신 백준 2110 문제에 대한 두 코드의 차이에 대해 설명드리겠습니다. 두 코드의 차이점은 isPossible 함수의 return 위치에 있습니다. 그렇다면 왜 이 차이가 오답을 초래하는지 설명해드리겠습니다.

문제 분석:

  1. isPossible(mid) 함수는 주어진 간격 mid로 공유기를 설치했을 때, C개의 공유기를 모두 설치할 수 있는지를 확인하는 함수입니다.
  2. 첫 번째 코드는 모든 집을 검사한 후 cnt >= C인지를 확인하여 답을 반환합니다.
  3. 두 번째 코드는 공유기 설치가 가능한지를 반복 과정 중에 계속 확인하여, 공유기 C개를 모두 설치할 수 있으면 즉시 true를 반환하고 그렇지 않으면 false를 반환합니다.

문제의 핵심:

  • 첫 번째 코드: 모든 집을 끝까지 확인한 후에야 설치 가능 여부를 판단합니다.
  • 두 번째 코드: 공유기 C개를 다 설치하자마자 판단을 중간에 합니다.

오답 코드의 문제점:

두 번째 코드의 문제점은 공유기 C개를 다 설치할 때만 true를 반환하고, 그 이전에 cnt가 원하는 수량 C의 조건에 도달하지 못하면 중간에 false를 반환하므로 특정한 경계값 상황에서 문제가 발생할 수 있습니다.

반례 예시:

예를 들어, 집의 위치가 [1, 2, 4, 8, 9]이고 공유기 개수가 3개일 때, 어떤 경우에는 임의의 mid 값이 정확한 경계값에서 체크가 누락되며 잘못된 답을 반환할 수 있습니다.

유사한 질문 및 답변:

강의의 관련 부분이나 설명이 포함된 기존 답변도 참조해 보시면 도움이 될 수 있습니다. 다음 링크들이 그러한 내용을 다루고 있습니다:

“고생했던? 케이스에 대해 선생님의 코드가 어떻게 들어맞는 지에 대한 질문이 있습니다. ㅠ”

이 게시물에서는 파라매트릭 서치 문제와 관련된 설명과 코드 차이에 대한 분석을 다루고 있습니다.

“저.. 시간복잡도 관련 질문입니다.(로직 거의 비슷한 거 같은데, 시간초과가 나서요)”

이 게시물에서는 시간복잡도와 관련된 문제 해결 방법을 다루며, 코드 효율성에 대한 부분을 상세히 설명하고 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.