현진 치킨에서 판매하는 치킨은 양념 치킨, 후라이드 치킨, 반반 치킨으로 총 세 종류이다. 반반 치킨은 절반은 양념 치킨, 절반은 후라이드 치킨으로 이루어져있다. 양념 치킨 한 마리의 가격은 A원, 후라이드 치킨 한 마리의 가격은 B원, 반반 치킨 한 마리의 가격은 C원이다.
상도는 오늘 파티를 위해 양념 치킨 최소 X마리, 후라이드 치킨 최소 Y마리를 구매하려고 한다. 반반 치킨을 두 마리 구입해 양념 치킨 하나와 후라이드 치킨 하나를 만드는 방법도 가능하다. 상도가 치킨을 구매하는 금액의 최솟값을 구해보자.
입력
첫째 줄에 다섯 정수 A, B, C, X, Y가 주어진다.
출력
양념 치킨 최소 X마리, 후라이드 치킨 최소 Y마리를 구매하는 비용의 최솟값을 출력한다.
제한
1 ≤ A, B, C ≤ 5,000
1 ≤ X, Y ≤ 100,000
반반 치킨을 두 마리 구입해 양념 치킨 하나와 후라이드 치킨 하나를 만드는 방법도 가능
양념 치킨 한 마리의 가격은 A원, 후라이드 치킨 한 마리의 가격은 B원, 반반 치킨 한 마리의 가격은 C원
히스토그램은 직사각형 여러 개가 아래쪽으로 정렬되어 있는 도형이다. 각 직사각형은 같은 너비를 가지고 있지만, 높이는 서로 다를 수도 있다. 예를 들어, 왼쪽 그림은 높이가 2, 1, 4, 5, 1, 3, 3이고 너비가 1인 직사각형으로 이루어진 히스토그램이다.
히스토그램에서 가장 넓이가 큰 직사각형을 구하는 프로그램을 작성하시오.
입력
입력은 테스트 케이스 여러 개로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있고, 직사각형의 수 n이 가장 처음으로 주어진다. (1 ≤ n ≤ 100,000) 그 다음 n개의 정수 h1, ..., hn(0 ≤ hi ≤ 1,000,000,000)가 주어진다. 이 숫자들은 히스토그램에 있는 직사각형의 높이이며, 왼쪽부터 오른쪽까지 순서대로 주어진다. 모든 직사각형의 너비는 1이고, 입력의 마지막 줄에는 0이 하나 주어진다.
높이 제한이 1000000000 (0이 9개)이고, N이 100000까지 가능하므로 높이를 기준으로 뭔가 하려는 순간 바로 시간 초과
고로 가로를 중심으로 보되 어떤 변화가 있는 부분( 높이의 대소관계가 변화는 지점 )을 중점적으로 본다
다음과 같은 입력이 있다고 가정하자
6 1 4 5 1 3 3
기본적으로 입력받은 순으로 스택에 넣는다
그 과정에서 일어날 수 있는 상황은 다음 두 가지밖에 없다
넣으려는 수가 이전 수보다 크거나 같다 (빨간 화살표) => 스택에 push
넣으려는 수가 이전 수보다 작다 (초록 화살표) => 스택에 있는 수들 중 넣으려는 수보다 큰 수들이 있는지 확인해준 후 push
특히 2번 경우를 잘 해결하는 것이 이 문제를 해결하는 것과 같다고 할 수 있다
이 상황이 언제 일어나는지 잘 기억해두자 ( 이하 '초록 화살표, 확인 상황'으로 통칭 )
확인하는 법
상황) 현재 i가 3이라서 i가 2일때 높이 (5)보다 높이 (1)이 작아서 확인하게 된 경우
스택에 들어있는 숫자들은 하늘색, 지금 기준이 되는 숫자는 초록색이라고 하자
i=2 일 때 만들 수 있는 최대 직사각형 = i=2일 때 높이 (5) x 너비 (3-1-1=1) = 5 (노란색)
i=1 일 때 만들 수 있는 최대 직사각형 = i=1일 때 높이 (4) x 너비 (3-1-0=2) = 8 (남색)
i=0 일 때 높이 = i=3일 때 높이이므로 확인 종료
이 과정에서 너비를 구하는 방법이 핵심이다
상황) 현재 i가 3이라서 i가 2일때 높이 (5)보다 높이 (1)이 작아서 확인하게 된 경우, 2는 이미 넓이 5로 확인 후 pop되었고, 다음 수인 1을 확인하려고 한다
1일 때 높이 4의 입장에서 보면 왼쪽에 0은 스택에 있고 오른쪽에 2는 스택에 없다
그리고 2는 현재 i인 3보다 작으므로, 높이 4보다 같거나 클 것임이 보장되어있다 ( 2의 높이가 만약 1의 높이보다 작았다면 이미 i = 2일 때 확인과정을 거쳐 스택에서 pop되었을 것이기 때문 )
따라서 높이는 4이고 너비는 좌우로 가능한 만큼 최대로 뻗어나갔을 때의 길이가 된다 (보라색선)
이때 가장 오른쪽은 현재 i 보다 1 작은 수일 것이고, 가장 왼쪽은 다음 stack에 맨 위에 있는 수+1일 것이다
$$ stack.top()+1 \leq x \leq i-1 $$
따라서 길이는 i-1-stack.top()
$$(i-1)-(s.top()+1)+1 = i-1-stack.top()$$
그런데 왼쪽에 더 이상 스택에 들어있는 수가 없을 수도 있다 이럴 경우에는 가장 왼쪽이 0이 되므로
$$ 0 \leq x \leq i-1 $$
따라서 길이는 i
9, 12번 줄 // 0을 받기 전까지 무한 반복 구현
14~16번 줄 // 수 입력받기
18번 줄 // 정답 받아줄 변수 선언 ( 0으로 초기화, long long )
19~28번 줄 // for문으로 가로를 기준으로 하나씩 확인
20~26번 줄 // 이번 문제의 핵심!
20번 줄 // while이 돌아가는 기준 잘 확인 ( 스택이 비어있지 않고 위의 "초록 화살표"일 경우 )
21~22번 줄 // 높이만 저장 후 스택에서 pop ( 이 시점부터 스택의 맨 위 stack.top()은 방금 뽑아낸 높이의 왼쪽에 있는 수 )
23~24번 줄 // 너비를 구해준다 ( 스택이 비었을 경우 i 아니면 i-1-stack.top() )
25번 줄 // 너비 * 높이로 넓이 구한 후 정답 변수 갱신 ( 이 때 형 변환 주의 !! )
27번 줄 // 왼쪽에 있으면서 현재 높이보다 큰 경우를 모두 확인했으므로 push
29~35번 줄 // 적절한 초록색 화살표를 만나지 못해 스택에 수가 남아있는 경우가 있다 이럴 경우에는 너비의 오른쪽 끝을 현재 i가 아닌 n으로 잡고 똑같은 while문을 돌려줌으로써 스택을 비워준다 ( 모든 경우의 수를 다 비교해본다 ) ( 제일 끝을 높이 -1의 임의의 초록색 화살표로 만들어 줬다고 생각하면 된다 )
주의사항
넓이는 int범위를 넘을 수 있다
int와 int를 곱하면 long long이 되지 않는다. 곱하기 전에 형변환을 해 줘야 한다 ( 풀이에는 처음부터 높이를 long long으로 변환해둠으로써 처리 )
한 달 후면 국가의 부름을 받게 되는 준서는 여행을 가려고 한다. 세상과의 단절을 슬퍼하며 최대한 즐기기 위한 여행이기 때문에, 가지고 다닐 배낭 또한 최대한 가치 있게 싸려고 한다.
준서가 여행에 필요하다고 생각하는 N개의 물건이 있다. 각 물건은 무게 W와 가치 V를 가지는데, 해당 물건을 배낭에 넣어서 가면 준서가 V만큼 즐길 수 있다. 아직 행군을 해본 적이 없는 준서는 최대 K무게까지의 배낭만 들고 다닐 수 있다. 준서가 최대한 즐거운 여행을 하기 위해 배낭에 넣을 수 있는 물건들의가치의 최댓값을 알려주자.
입력
첫 줄에 물품의 수 N(1 ≤ N ≤ 100)과 준서가 버틸 수 있는 무게 K(1 ≤ K ≤ 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 ≤ W ≤ 100,000)와 해당 물건의 가치 V(0 ≤ V ≤ 1,000)가 주어진다.
입력으로 주어지는 모든 수는 정수이다.
출력
한 줄에 배낭에 넣을 수 있는 물건들의 가치합의 최댓값을 출력한다.
N개의 물건 N(1 ≤ N ≤ 100)
무게 W W(1 ≤ W ≤ 100,000)
가치 V V(0 ≤ V ≤ 1,000)
최대 K무게 K(1 ≤ K ≤ 100,000)
배낭에 넣을 수 있는 물건들의가치의 최댓값
채점 결과
풀이 (C++)
iostream
vector
algorithm
동적 계획법
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
#include<iostream>
#include<vector>
#include<algorithm>
usingnamespacestd;
struct product {
int w, v;
};
int main() {
int n, k;
cin>> n >> k;
vector<product> bag(n +1);
int dp[101][100001] = { 0 };
for (int i =1; i <= n; i++) {
cin>> bag[i].w >> bag[i].v;
}
for (int i =1; i <= n; i++) {
for (int j =0; j <= k; j++) {
dp[i][j] = dp[i -1][j];
}
if (bag[i].w <= k) dp[i][bag[i].w] = max(dp[i][bag[i].w], bag[i].v);