728x90
시간 제한 1초, 메모리 제한 1024MB
# 조건
- 총 N일 동안 빈 회의장에 늑대와 양이 모이기로 했다. 첫 번째 날부터 N 번째 날까지 매일 양 또는 늑대 한 마리가 회의장에 도착한다.
- 첫 번째 날에는 항상 양이 도착하고 마지막 날에는 항상 늑대의 수가 양의 수보다 많다.
- 늑대와 양의 수가 같아지면 늑대가 양을 잡아먹을 수도 있어 늑대와 양의 수가 같아지는 모든 날에 회의장에 무지가 출근하게 된다.
- 무지의 친구인 당신은 무지가 출근하는 날을 알고 싶다.
- 무지가 언제 출근하는 지 알기 위해 시스템에 특정한 날에 회의장에 있는 양의 수를 물어보고자 한다.
- 최대 20번의 질의를 통해 무지가 출근하는 날을 아무 날이나 하나 출력한다. 만약 그러한 날이 없는 경우
! 0
을 출력한다. - **시스템은 여러분의 질문에 따라 특정 날에 도착한 동물의 정보를 바꾸지 않는다.
- 즉, 이전까지의 답변들과 모순되는 답변은 하지 않는다.
입력
- 입력의 첫 줄에 정수 N이 주어진다. (3<=N<=100,000)
출력
- 다음을 표준 출력 스트림(stdout)으로 한 줄에 출력하여, i번째 날에 회의장에 있는 양의 수를 질의할 수 있다.
- 질의에 대한 답변은 정수로 주어진다.
? i
: i번째 날 회의장에 있는 양의 수$\left(1 \le i \le N\right)$- 각 질문을 출력한 후에는 반드시 표준 출력 버퍼를 flush 해야 하고, 표준 입력 스트림(stdin)을 통해 질문에 대한 답을 입력받아야 한다.
- 그렇지 않으면, 시간 초과 또는 런타임에러를 받는다.
- 질문하는 i의 범위가 날짜 구간을 벗어나는 경우, 틀렸습니다를 받는다.
- 질문은 최대 20번만 할 수 있고, 이보다 더 많이 질문을 하면 틀렸습니다를 받는다.
- 최대 20번의 질문을 이용해, 정답을 아래의 표준 출력 스트림(stdout)을 이용해 한 번만 출력한다.
! T
$\left( 0 \le T \le N\right)$- 그 후 반드시 표준 출력 버퍼를 flush해야 하고, 프로그램을 종료한다.
- 이것은 질문 횟수에 포함되지 않는다.
- 언어 별로 표준 출력 버퍼를 flush하는 방법은 다음과 같다.
- C:
fflush(stdout)
- C++:
std::cout << std::flush
- Java:
System.out.flush()
- Python:
sys.stdout.flush()
- C:
**# 인터렉티브
- 백준에서 인터렉티브 문제를 보는건 처음이다.
- 인터렉티브 문제란 서버와 나의 코드가 서로 질의응답과 같은 상호작용을 하는 문제이다.
- 인터렉티브 문제는 입출력이 상당히 느리기 때문에 시스템 입출력을 사용해주어야 하고 버퍼에 대해 알아야 한다.
- 버퍼는 임시 메모리 공간을 가지고 있는데 이 중 입출력 버퍼는 입력된 데이터나 출력 장치로 보내기 전에 데이터를 일시 저장한다.
- 채점 프로그램에서 이런 방식은 제대로 돌아가지 않을 수 있기 때문에 **플러쉬(FLUSH)를 사용하여 지속적으로 버퍼를 비워주어야 한다.
- 인터렉티브 문제의 특징은 스스로 질문자가 되어야 하기에 디버깅이 불가능하다.
# 접근 방법
- 문제를 읽다보니 스무고개와 비슷하다는 생각이 들었다.
- 첫 날에는 항상 양이 도착하고, 마지막 날에는 항상 늑대의 수가 양의 수보다 많다.
- 매일 양 또는 늑대 한 마리가 도착한다.
- 또한, 늑대와 양의 수가 같으면 늑대가 양을 잡아먹을 수도 있기에 늑대와 양의 수가 같아지는 모든 날에는 무지가 출근한다.
- 이분탐색을 이용하여 풀어주면 될 것 같다.
- start = 1, end = 주어진 N으로 시작하여 질문이 20개까지만 하도록 while문을 돌려준다.
- mid를 (start+end) // 2로 print(? mid)를 해주면 그 날의 양의 수가 입력으로 들어온다.
- 이 때, mid(날짜) - val(그날의 양의 수) == val 이라면 늑대와 양의 수가 동일하다는 뜻이다.
- 매일 한 마리의 양 또는 한 마리의 늑대가 오므로
- 같은 경우 무지가 출근 했으므로 print(! mid) 후 exit()
- 만약 mid - val > val 이라면 늑대의 수가 많으므로 end = mid - 1
- mid + val < val 이라면 양의 수가 많으므로 start = mid + 1
import sys
input = sys.stdin.readline
N = int(input())
start = 1
end = N
cnt = 0
while cnt < 20:
mid = (start + end) // 2
print(f'? {mid}')
sys.stdout.flush()
val = int(input())
if mid - val == val:
print(f'! {mid}')
sys.stdout.flush()
exit()
elif mid - val > val:
end = mid - 1
elif mid -val < val:
start = mid + 1
cnt += 1
728x90
'ALGORITHM > 정렬, 탐색,구현' 카테고리의 다른 글
[백준 2632번] 파이썬 - 피자판매 (0) | 2023.08.08 |
---|---|
[백준 16916번] 파이썬 - 부분 문자열 (0) | 2023.08.07 |
[프로그래머스 Lv3] 파이썬 - 파괴되지 않은 건물 (0) | 2023.08.03 |
[백준 1182번] 파이썬 - 부분 수열의 합 (0) | 2023.07.24 |
[백준 18500번] 파이썬 - 미네랄 2 (0) | 2023.07.19 |