B2805

개요

백준 문제 2805번을 풀면서 어려웠던 점과 코드를 정리한다.
소요 시간 : 60분
https://www.acmicpc.net/problem/2805

문제

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

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

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

코드

#include
using namespace std;
const long long MAX = 1000000;
const long long INF = 987654321;
long long tree[MAX];
long long count;
long long maxCuttingHeight = 0;

bool isCutted(long long idx,long long cuttingHeight)
{
if(tree[idx] > cuttingHeight)
{
return true;
}
return false;
}

void binarySearch(long long start,long long end,long long wantedHeight)
{

if(start > end)
{
    cout << maxCuttingHeight;
    return;
}
long long cuttingHeight = (start + end) / 2;
long long cutResult = 0;
for(long long i=0;i<count;i++)
{
    if(isCutted(i,cuttingHeight))
    {
        cutResult += tree[i] - cuttingHeight;
    }
}
if(wantedHeight <= cutResult)
{
    maxCuttingHeight = max(maxCuttingHeight,cuttingHeight);
    binarySearch(cuttingHeight+1,end,wantedHeight);
}
else
{
    binarySearch(start,cuttingHeight-1,wantedHeight);
}

}

void solve()
{
long long N,wantedHeight;
long long maxHeight = 0;
cin >> N >> wantedHeight;

for(count=0;count<N;count++)
{
    cin >> tree[count];
    maxHeight = max(maxHeight,tree[count]);
}
binarySearch(0,maxHeight,wantedHeight);

}

int main()
{
solve();
}

풀이

이진탐색 응용문제로,
입력 중 가장 큰 값을 토대로 이진탐색을 진행한다.
진행하며 조건에 맞는 값 중 가장 큰 값을 찾는다.
조심할 점은 입력으로 1 1 1이 주어진 경우 절단기의 높이가 0이어야하므로
시작점을 0으로 설정해야 한다.
또한 범위에 유의하여 자료형을 설정해야 한다.

배울 점, 메모

B1654

개요

백준 문제 A번을 풀면서 어려웠던 점과 코드를 정리한다.
소요 시간 : 1분
https://www.acmicpc.net/problem/1654

문제

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

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

편의를 위해 랜선을 자르거나 만들 때 손실되는 길이는 없다고 가정하며, 기존의 K개의 랜선으로 N개의 랜선을 만들 수 없는 경우는 없다고 가정하자. 그리고 자를 때는 항상 센티미터 단위로 정수길이만큼 자른다고 가정하자. N개보다 많이 만드는 것도 N개를 만드는 것에 포함된다. 이때 만들 수 있는 최대 랜선의 길이를 구하는 프로그램을 작성하시오.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
using namespace std;
const long long MAX = 10000;
long long line[MAX];
long long count = 0;

long long resultLen = 0;

long long binarySearch(long long start,long long end,long long objVal)
{
long long divUnit = (start + end) / 2;
long long lineCount = 0;
if(start > end)
{
return 0;
}
for(long long i=0;i<count;i++)
{
lineCount += (line[i] / divUnit);
}

if(lineCount >= objVal)
{
if(resultLen < divUnit)
{
resultLen = divUnit;
}

binarySearch(divUnit+1,end,objVal);
return divUnit;
}
else
{
return binarySearch(start,divUnit-1,objVal);
}
}

void solve()
{
long long haveLine,makeLine;
cin >> haveLine >> makeLine;
long long maxLen = 0;
long long result = 0;
for(count=0;count<haveLine;count++)
{
cin >> line[count];
result += line[count];
maxLen = max(maxLen,line[count]);
}
binarySearch(1,maxLen,makeLine);
cout << resultLen;
}


int main()
{
solve();

}

풀이

우선 이분탐색으로 풀이하는 문제임을 안 상태였고,
따라서 이분탐색을 이용하여서 풀 수 있는 방법을 생각해보면
최대 랜선 길이를 end라 두고 이분탐색을 진행하면 된다.
이 때, 원하는 개수를 만들었더라도 최대 길이를 찾아야 하므로
최대 개수를 찾은 상태 -> 원하는 개수가 만들어지지 않을 때 까지 계산하여 최대 길이를 찾으면 된다.

배울 점, 메모

풀이방법 자체는 잘 생각했으나,
이분탐색에서 왼쪽 탐색 시 end = mid -1, 오른쪽 탐색 시 start = mid + 1를 명시해야 하는데 이 부분 미흡했다.
또한 입력 값의 범위가 int로 주어지지만 계산 시 int 범위를 넘어가기 때문에 long long으로 바꿔줘야 한다.

B2004

개요

백준 문제 2004번을 풀면서 어려웠던 점과 코드를 정리한다.
소요 시간 : 1시간 30분
https://www.acmicpc.net/problem/2004

문제

nCm의 끝자리 의 개수를 출력하는 프로그램을 작성하시오.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
using namespace std;

long long getCountFromFact(long long n)
{
long long five = 0;
for(long long i=5;i<=n;i*=5)
{
five += n/i;
}
return five;
}

long long getCountFromFactTwo(long long n)
{
long long two = 0;
for(long long i=2;i<=n;i*=2)
{
two += n/i;
}
return two;
}


int getCountFromNum(string str)
{
int count = 0;
for(int i=str.size()-1;i>=0;i--)
{
if(str[i] != '0')
{
return count;
}
count++;
}
}


void solve()
{
long long n,c;
cin >> n >> c;
c = min(n-c,c);
long long upper,mid;
long long upperTwo,midTwo;
if(c == 0)
{
cout << 0;
}
else if(c == 1)
{
cout << getCountFromNum(to_string(n));
}
else
{
upper = getCountFromFact(n);
mid = getCountFromFact(n-c) + getCountFromFact(c);
upperTwo = getCountFromFactTwo(n);
midTwo = getCountFromFactTwo(n-c) + getCountFromFactTwo(c);

cout << min((upper - mid),(upperTwo-midTwo));
}

}


int main()
{
solve();
}

풀이

이전에 배웠던 팩토리얼을 직접 계산하지않고 0을 추출하는 것을 이용한 문제이다.
(2와 5의 쌍의 갯수를 계산하여 푸는 방법)
팩토리얼 0의 갯수 구하기 문제에서는 2가 의미가 없었다 (항상 5의 개수가 적어서)
하지만 이번 문제도 동일하게 생각해서 풀었는데, 나눠지는 팩토리얼에서 2를 나누면
나누는 팩토리얼에 영향을 주게되므로 2의 개수도 고려해야 했다.

배울 점, 메모

오늘로 6문제를 풀어보았는데,
스스로 완벽하게 푼 문제는 기초문제들 뿐이었다.
하지만 어떡하겠는가?
완벽하게 안다면 배울 필요가 없지 않는가

B1676

개요

백준 문제 1676번을 풀면서 어려웠던 점과 코드를 정리한다.
소요 시간 : 30분
https://www.acmicpc.net/problem/1676

문제

N!에서 뒤에서부터 처음 0이 아닌 숫자가 나올 때까지 0의 개수를 구하는 프로그램을 작성하시오.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;


void solve()
{
int num = 0;
cin >> num;
int five=0;
for(int i=5;i<=num;i*=5)
{
five += num / i;
}
cout << five;
}



int main()
{
solve();
}

풀이

우선 팩토리얼을 그대로 연산하면 시간초과가 뜬다는 것을 파악했다.
그렇다면 팩토리얼 연산을 하지 않고 어떻게 0의 개수를 파악할까?
정답은 0의 개수 = 10의 개수였다.
따라서 어떤 숫자 N에 대해 2와 5의 갯수를 찾고
그 중 최소값(여기서 최소값은 2와 5가 쌍을 이룰 수 있는 개수)를 찾으면 된다.
하지만 생각해보면 5의 개수는 항상 2의 개수보다 적다 따라서 2는 무시하고 5의 개수만 찾으면 된다.

배울 점, 메모

보통 이런 수학 문제를 만나면 머리가 멍해지는데,
문제를 작게 분해하고 규칙을 찾는 것이 중요한 것 같다.