문제:

아래의 그림과 같이 높은 빌딩 사이를 따라 좁은 길이 나있다. 두 개의 사다리가 있는데 길이가 x인 사다리는 오른쪽 빌딩의 아래를 받침대로 하여 왼쪽 빌딩에 기대져 있고 길이가 y인 사다리는 왼쪽 빌딩의 아래를 받침대로 하여 오른쪽 빌딩에 기대져 있다. 그리고 두 사다리는 땅에서부터 정확하게 c인 지점에서 서로 교차한다. 그렇다면 두 빌딩은 얼마나 떨어져 있는 걸까?

입력:

첫째 줄에 차례대로 x,y,c에 해당하는 양의 실수 세 개가 입력된다. 수는 소수점 여섯째 자리까지 주어질 수 있다.

 

출력:

두 빌딩사이에 너비가 되는 수치를 출력한다. 절대/상대 오차는 10^-3까지 허용한다.

 

풀이방법:

 이분 탐색을 기반으로 하지만 수학적인 내용이 더 많이 들어가는 문제인 것 같다. 문제의 기본 틀은 두 빌딩 사이의 거리를 d라고 했을 때, 이를 이분 탐색으로 값을 바꾸어 간다. 임의의 d에 따라서 사다리가 교차하는 높이 h가 달라질 것이다. 따라서 이분탐색을 통해서 그 중 c와 같아지는 d를 찾도록 한다.

 임의의 d에 따라서 h를 구하는 방법은 수학의 닮음을 사용하도록 해야 한다. 사다리가 교차하는 높이를 h라 하고 선을 다음과 같이 그리면 닮음 꼴인 직각 삼각형을 얻을 수 있다.

h라는 직선이 생김에 따라 d도 d1과 d2로 나뉘게 될 것이고, h1과 h2도 다음과 같이 정의를 할 수 있을 것이다.

그러면 빗변이 x인 삼각형과 y인 삼각형에 각각 다음과 같은 닮음비를 얻을 수 있다.

 

[위]빗변이 x, [아래]빗변의 y

 우리가 최종적으로 원하는 변수는 h이기 때문에 h=( ~ ) 와 같은 형태로 변형시켜야 할 것이다. 그러기 위해서는 d1+d2 = d임을 알고 있기 때문에 이를 활용해서 변수를 줄이도록 하자.

 

닮음비의 성질
d1과 d2에 관한 식으로 정리

그러기 위해서는 일단 닮음비를 정리해서 d1과 d2에 관한 식으로 만들었다. 그리고 난 뒤에 위 두 식을 더한다면 d1과 d2를 d로 바꿀 수 있게 될 것이다.

 

d1+d2=d이다.

 이제 양변을 각각 d로 나눌 수 있을 것이다. d는 두 빌딩 사이의 거리이므로 0을 초과한 거리일 것이다. 따라서 양변을 나누는 것에 문제가 없다.

 그러면 위 그림의 제일 위의 식과 같이 얻을 수 있을 것이고 좌변을 h에 대해서 묶을 수 있게 될 것이다. 좌변을 h로 묶고 난 뒤에 남은 것들을 우변으로 넘겨준다면 이를 h에 대한 식으로 만들 수 있을 것 이다. 따라서 위 그림의 두번째와 세번째 식은 그 과정을 담고 있다.

 h1과 h2는 x, y, d로 이루어진 변수이기 때문에 정확한 값을 계산할 수 있다. (d는 이분 탐색으로 정해진 값이다.) 따라서 h의 값을 구할 수 있을 것이고 이를 c와 비교하면서 c에 근접하게 d를 이분탐색으로 찾을 수 있을 것이다.

그렇게 찾은 mid값을 소숫점 셋째 자리까지 반올림해서 출력하도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import math
x,y,c=map(float,input().split())
left,right=0,min(x,y)
while(abs(right-left)>1e-6):
    mid=(left+right)/2.0
    d=mid
    h1=math.sqrt(x*x-d*d)
    h2=math.sqrt(y*y-d*d)
    h=(h1*h2)/(h1+h2)
    if h > c:
        left=mid
    else:
        right=mid
print("%.3f"%round(mid,3))
cs

문제링크:

https://www.acmicpc.net/problem/2022

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]14889. 스타트와 링크  (0) 2019.09.23
[BOJ]1697. 숨바꼭질  (0) 2019.09.22
[BOJ]1561. 놀이공원  (0) 2019.09.20
[BOJ]1080. 행렬  (0) 2019.09.19
[BOJ]10610. 30  (0) 2019.09.18

문제:

N명의 아이들이 한 줄로 줄을 서서 놀이공원에서 1인승 놀이기구를 기다리고 있다. 이 놀이공원에는 총 M종류의 1인승 놀이기구가 있으며, 1번부터 M번까지 번호가 매겨져 있다.

모든 놀이기구는 각각 운행 시간이 정해져 있어서, 운행 시간이 지나면 탑승하고 있던 아이는 내리게 된다. 놀이 기구가 비어 있으면 현재 줄에서 가장 앞에 서 있는 아이가 빈 놀이기구에 탑승한다. 만일 여러 개의 놀이기구가 동시에 비어 있으면, 더 작은 번호가 적혀 있는 놀이기구를 먼저 탑승한다고 한다.

놀이기구가 모두 비어 있는 상태에서 첫 번째 아이가 놀이기구에 탑승한다고 할 때, 줄의 마지막 아이가 타게 되는 놀이기구의 번호를 구하는 프로그램을 작성하시오.

 

입력:

첫째 줄에 N(1<=N<=2,000,000,000)과 M(1<=M<=10,000)이 빈칸을 사이에 두고 주어진다. 둘째 줄에는 각 놀이기구의 운행 시간을 나타내는 M개의 자연수가 순서대로 주어진다. 운행 시간은 1 이상 30 이하의 자연수이며, 단위는 분이다.

 

출력:

첫째 줄에 마지막 아이가 타게 되는 놀이기구의 번호를 출력한다.

 

풀이 방법:

이분 탐색을 사용해서 풀어야 하는 문제이다. 항상 이러한 이분 탐색을 사용해서 푸는 문제들은 찍어서 최적의 값을 맞춰나간다 라는 느낌이 강하다. 따라서 이 문제도 역시 일정 값을 찍어서 근처로 구하고 그 값으로 부터 놀이기구의 번호를 찾도록 하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
n,m=map(int,input().split())
times=list(map(int,input().split()))
left,right=0,10**20
answer=0
B_p=0
while(left<=right):
    mid=(left+right)//2
    temp=0
    for time in times:
        temp += ((mid-1)//time)+1
    if temp < n:
        if answer < mid:
            answer = mid
            B_p = temp
        left = mid + 1
    else:
        right = mid - 1
for i in range(m):
    if answer%times[i]==0:
        B_p+=1
        if B_p == n:
            print(i+1)
            break
cs

문제링크:

https://www.acmicpc.net/problem/1561

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]1697. 숨바꼭질  (0) 2019.09.22
[BOJ]2022. 사다리  (0) 2019.09.21
[BOJ]1080. 행렬  (0) 2019.09.19
[BOJ]10610. 30  (0) 2019.09.18
[BOJ]2875. 대회 or 인턴  (0) 2019.09.17

문제:

상근이는 나무 M미터가 필요하다. 근처에 나무를 구입할 곳이 모두 망해버렸기 때문에, 정부에 벌목 허가를 요청했다. 정부는 상근이네 집 근처의 나무 한 줄에 대한 벌목 허가를 내주었고, 상근이는 새로 구입한 목재절단기를 이용해서 나무를 구할 것이다.

목재절단기를 다음과 같이 동작한다. 먼저, 상근이는 절단기에 높이 H를 지정해야 한다. 높이를 지정하면 톱날이 땅으로부터 H미터 위로 올라간다. 그 다음, 한 줄에 연속해있는 나무를 절단해버린다. 따라서, 높이가 H보다 큰 나무는 H 위의 부분이 잘릴 것이고, 낮은 나무는 잘리지 않을 것이다. 예를 들어, 한 줄에 연속해있는 나무의 높이가 20,15,10,17이라고 하자. 상근이가 높이를 15로 지정했다면, 나무를 자른 뒤의 높이는 15,15,10,15가 될 것이고, 상근이는 길이가 5인 나무와 2인 나무를 들고 집에 갈 것이다. (총 7미터를 집에 들고 간다.)


상근이는 환경에 매우 관심이 많기 때문에, 나무를 필요한 만큼만 집으로 가져가려고 한다. 이 때, 적어도 M미터의 나무를 집에 가져가지 위해서 절단기에 설정할 수 있는 높이의 최댓값을 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. (1<=N<=1,000,000, 1<=M<=2,000,000,000)
둘째 줄에는 나무의 높이가 주어진다. 나무의 높이의 합은 항상 M을 넘기 때문에, 상근이는 집에 필요한 나무를 항상 가져갈 수 있다. 높이는 1,000,000,000보다 작거나 같은 양의 정수 또는 0이다.

출력:

적어도 M미터의 나무를 집에 가져가기 위해서 절단기에 설정할 수 있는 높이의 최댓값을 출력한다.

풀이 방법:

이 문제도 이분탐색(파라메트릭서치)를 사용해서 풀어야 하는 문제다. left를 1, right를 max(trees)로 잡고 나서 그 사이의 값을 찍어가면서 M보다 커질 때마다 mid을 비교해 최대값을 찾도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
k,n=map(int,input().split())
trees=list(map(int,input().split()))
left=1
right=max(trees)
answer=0
while left <= right:
    count=0
    mid=(left+right)//2
    for tree in trees:
        if tree-mid > 0:
            count+=tree-mid
    if count==n:
        if answer < mid:
            answer=mid
        left=mid+1
    elif count < n:
        right=mid-1
    else:
        if answer < mid:
            answer=mid
        left=mid+1
print(answer)
cs

문제 링크:


'Algorithm > Python' 카테고리의 다른 글

[Programmers]Lv3. 가장 먼 노드  (0) 2019.07.29
[Programmers]Lv 4. 3xn 타일링  (2) 2019.07.28
[BOJ]1654.랜선 자르기  (0) 2019.07.26
[BOJ]10816. 숫자 카드2  (0) 2019.07.25
[BOJ]1920. 수 찾기  (0) 2019.07.24

문제:

집에서 시간을 보내던 오영식은 박성원의 부름을 받고 급히 달려왔다. 박성원이 캠프 때 쓸 N개의 랜선을 만들어야 하는데 너무 바빠서 영식이에게 도움을 청했다.

이미 오영식은 자체적으로 K개의 랜선을 가지고 있다. 그러나 K개의 랜선은 길이가 제각각이다. 박성원은 랜선을 모두 N개의 같은 길이의 랜선으로 만들고 싶었기 때문에 K개의 랜선을 잘라서 만들어야 한다. 예를 들어 300cm 짜리 랜선에서 140cm 짜리 랜선을 두 개 잘라내면 20cm은 버려야 한다. (이미 자른 랜선은 붙일 수 없다.)

편의를 위해 랜선을 자르거나 만들 때 손실되는 길이는 없다고 가정하며, 기존의 K개의 랜선으로 N개의 랜선을 만들 수 없는 경우는 없다고 가정하자. 이때 만들 수 있는 최대 랜선의 길이를 구하는 프로그램을 작성하시오.

입력:

첫째 줄에는 오영식이 이미 가지고 있는 랜선의 개수 K, 그리고 필요한 개수 N이 입력된다. K는 1이상 10,000이하의 정수이고, N은 1이상 1,000,000이하의 정수이다. 그리고 항상 K<=N이다. 그 후 K줄에 걸쳐 이미 가지고 있는 각 랜선의 길이가 센티미터 단위로 정수로 입력된다. 랜선의 길이는 2^31보다 작거나 같은 자연수이다.

출력:

첫째 줄에 N개를 만들 수 있는 랜선의 최대 길이를 센티미터 단위의 정수로 출력한다.

풀이 방법:

 이분 탐색을 사용해서 풀어야 하는 문제이다. 바이너리서치가 아닌 파라메트릭 서치를 사용하는 것이다, 이 문제의 핵심은 잘 찍어내는 것으로 최솟값과 최대값을 고르면 그 사이를 탐색하면서 잘 찍은 값을 반환하는 것이다. 이 잘 찍는 과정은 이분 탐색을 근거로 하게 된다.
 
 이 문제도 left를 1로(0으로 하면 런타임 에러(0으로 나눈 에러)가 발생한다.) right는 내가 가지고 있는 선 중 가장 큰 값으로 사용했다. 이 left값과 right값을 통해서 mid값을 구했고, 이를 lines를 순회하며 count를 계산했고 n과 같아지는 순간에 mid값 중 가장 큰 값을 고르도록 하였다.하지만 이렇게 했을 때 계속 문제를 틀렸다고 결과를 받았다.
 
 무엇이 문제인지 알아보니 만약 K개의 랜선으로 N개 이상을 만들어도 N개를 사용하고 나머지는 버려서 사용할 수 있기 때문에 count > n일 때도 mid 값을 answer에 업데이트 해야한다고 한다. 따라서 이에 맞게 수정을 했더니 통과를 했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
k,n=map(int,input().split())
lines=[]
for i in range(k):
    lines.append(int(input()))
left=1
right=max(lines)
answer=0
while left <= right:
    count=0
    mid=(left+right)//2
    for line in lines:
        count+=line//mid
    if count==n:
        if answer < mid:
            answer=mid
        left=mid+1
    elif count < n:
        right=mid-1
    else:
        if answer < mid:
            answer=mid
        left=mid+1
print(answer)
cs


문제 링크:


'Algorithm > Python' 카테고리의 다른 글

[Programmers]Lv 4. 3xn 타일링  (2) 2019.07.28
[BOJ]2805. 나무 자르기  (0) 2019.07.27
[BOJ]10816. 숫자 카드2  (0) 2019.07.25
[BOJ]1920. 수 찾기  (0) 2019.07.24
[BOJ]2075. N번째 큰 수  (0) 2019.07.23

문제:

숫자 카드는 정수 하나가 적혀져 있는 카드이다. 상근이는 숫자 카드 N개를 가지고 있다. 정수 M개가 주어졌을 때, 이 수가 적혀있는 숫자 카드를 상근이가 몇 개 가지고 있는지 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 (1<=N<=500,000)가 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,000,000보다 작거나 같다.

셋째 줄에는 M(1<=M<=500,000)이 주어진다. 넷째 줄에는 상근이가 몇 개 가지고 있는 숫자 카드인지 구해야 할 M개의 정수가 주어지면, 이 수는 공백으로 구분되어져 있다. 이수도 -10,000,000보다 크거나 같고, 10,000,000보다 작거나 같다.

출력:

첫째 줄에 입력으로 주어진 M개의 수에 대해서, 각 수가 적힌 숫자 카드를 상근이가 몇 개 가지고 있는지를 공백으로 구분해 출력한다.

풀이 방법:

이진 탐색을 사용하면 쉽게 구할 수 있다. 만약 10의 개수가 궁금하다고 가정하자 그러면 10의 bisect_left의 인덱스와 11의 bisect_left를 구하면 10의 개수를 쉽게 얻을 수 있다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
import bisect
n=int(input())
arr = list(map(int,input().split()))
arr.sort()
m=int(input())
check=list(map(int,input().split()))
for i in range(m):
    idx1=bisect.bisect_left(arr,check[i])
    if idx1 <len(arr) and arr[idx1]==check[i]:
        idx2=bisect.bisect_left(arr,check[i]+1)
        print(idx2-idx1,end=' ')
    else:
        print(0,end=' ')
cs


'Algorithm > Python' 카테고리의 다른 글

[BOJ]2805. 나무 자르기  (0) 2019.07.27
[BOJ]1654.랜선 자르기  (0) 2019.07.26
[BOJ]1920. 수 찾기  (0) 2019.07.24
[BOJ]2075. N번째 큰 수  (0) 2019.07.23
[BOJ] 11279,1927,11286 최대힙,최소힙,절대값 힙  (0) 2019.07.21

문제:

N개의 정수 A[1], A[2], ... , A[N]이 주어져 있을 때, 이 안에 X라는 정수가 존재하는지 알아내는 프로그램을 작성하시오.

입력:

첫째 줄에 자연수 N(1<=N<=100,000)이 주어진다. 다음 줄에는 N개의 정수 A[1], A[2], ... , A[N]이 주어진다. 다음줄에는 M(1<=M<=100,000)이 주어진다. 다음 줄에는 M개의 수들이 주어지는데, 이 수들이 A안에 존재하는지 알아내면 된다. 모든 정수들의 범위는 int로 한다.

출력:

M개의 줄에 답을 출력한다. 존재하면 1을, 존재하지 않으면 0을 출력한다.

풀이 방법:

binary_search를 사용하는 문제이다. python에 이진탐색을 지원하는 bisect라는 모듈이 있다. 따라서 이를 사용하면 쉽게 문제를 풀 수 있다. bisect의 모듈은 binary search를 직접적으로 지원을 하지 않기 때문에 따로 만들어줘야 한다. bisect에 bisect_left(arr,x)와 bisect_right(arr,x)가 있는데, 각각 arr에 x를 넣어야 할 때 어느 인덱스에 넣어야 할지 알려주는 함수이다.(left는 왼쪽에, right는 오른쪽에) 따라서 bisect_left를 사용하면 binary_search를 구현할 수 있다. 만약 기존 arr에 있는 값을 찾는다고 하면(넣으려고 한다면) 왼쪽 인덱스를 반환해주므로 원래의 위치를 return 해준다. 따라서 그 인덱스에  해당하는 배열 값과 x가 같으면 존재하고, 같지 않다면 존재하지 않다고 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import bisect
def binary_search(arr,x):
    i = bisect.bisect_left(arr,x)
    return i < len(arr) and arr[i]==x
n=int(input())
arr = list(map(int,input().split()))
arr.sort()
m=int(input())
check=list(map(int,input().split()))
for i in range(m):
    if binary_search(arr,check[i]):
        print(1)
    else:
        print(0)
cs


'Algorithm > Python' 카테고리의 다른 글

[BOJ]1654.랜선 자르기  (0) 2019.07.26
[BOJ]10816. 숫자 카드2  (0) 2019.07.25
[BOJ]2075. N번째 큰 수  (0) 2019.07.23
[BOJ] 11279,1927,11286 최대힙,최소힙,절대값 힙  (0) 2019.07.21
[BOJ]2606. 바이러스  (0) 2019.07.20

문제:

국가의 역할 중 하나는 여러 지방의 예산요청을 심사하여 국가의 예산을 분배하는 것입니다. 국가예산의 총액은 미리 정해져 있어서 모든 예산요청을 배정해 주기는 어려울 수도 있습니다. 그래서 정해진 총액 이하에서 가능한 한 최대의 총 예산을 다음과 같은 방법으로 배정합니다.

1. 모든 요청이 배정될 수 있는 경우에는 요청한 금액을 그대로 배정합니다.
2. 모든 요청이 배정될 수 없는 경우에는 특정한 정수 상한액을 계산하여 그 이상인 예산요청에는 모두 상한액을 배정합니다.
   상한액 이하의 예산요청에 대해서는 요청한 금액을 그대로 배정합니다.

예를 들어, 전체 국가예산이 485이고 4개 지방의 예산요청이 각각 120,110,140,150일 때, 상한액을 127로 잡으면 위의 요청들에 대해서 각각 120,110,127,127을 배정하고 그 합이 484로 가능한 최대가 됩니다.
각 지방에서 요청하는 예산이 담긴 배열 budgets과 총 예산 M이 매개변수로 주어질 때, 위의 조건을 모두 만족하는 상한액을 return 하도록 solution 함수를 작성해주세요.

풀이 방법:

이 문제는 처음 봤을 때, 예시를 보면 120~150 사이의 수를 모두 넣어보아서 최대가 되는 상한액을 찾으면 되는 것이 아닌가 라고 생각 할 수 있지만 그렇게 푼다면 아마 시간초과가 발생할 것이다.(총 예산이 1,000,000,000 이하인 수이다..)
따라서 이 문제의 태그가 이분탐색인 만큼 이분탐색을 사용해야 시간초과가 발생하지 않고 풀 수 있다. 이분탐색의 문제의 핵심은 '찍기'라고 생각하면 된다. 이 문제의 예시로 예를 들어보면 0~150의 수를 이분탐색의 방법으로 찍어가면서 최대 상한액을 찾아나가는 것이다.

처음에는 75를 상한액으로 고를 수 있고 75*4<=485이므로 왼쪽 값을 75+1로 선택하여 이분탐색을 진행한다.
그 다음엔 113을 상한액으로 고를 수 있고 이 역시 113*3+110<=485이므로 왼쪽값을 113+1로 선택하여 이분탐색을 진행한다.
그 다음엔 132를 상한액으로 고를 수 있고 120+110+132*2>=485이므로 오른쪽 값을 132-1로 선택하여 이분탐색을 진행한다.
이와 같이 계속 반복하다보면 127이 상한액일 때 최대가 됨을 알 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def solution(budgets, M):
    left=0
    right=max(budgets)
    temp=0
    answer=0
    while(right>=left):
        mid=(left+right)//2
        result=0
        for i in budgets:
            if mid>i:
                result+=i
            else:
                result+=mid
        if result>M:
            right=mid-1
        else:
            if result>=temp:
                answer=mid
            left=mid+1
    return answer
cs


'Algorithm > Python' 카테고리의 다른 글

[Programmers]Lv 3. 정수 삼각형  (0) 2019.02.27
[Programmers]Lv 2. 카펫  (0) 2019.02.26
[Programmers]Lv 2. 구명 보트  (0) 2019.02.24
[Programmers]Lv 3.타일 장식물  (0) 2019.02.23
[Programmers]Lv 2. 숫자 야구  (0) 2019.02.22

+ Recent posts