백준 13448번 SW 역량 테스트
문제
SW 역량 테스트는 총 T분동안 진행되며 N개의 문제가 나온다. 대회가 진행되는 동안 아무 때나 소스 코드를 제출할 수 있다.
i번 문제를 t분에 맞춘 경우에는 Mi-t*Pi 점을 받게 된다. 이 테스트에 응시한 백준이가 i번 문제를 푸는데 걸리는 시간은 Ri분이다.
백준이가 얻을 수 있는 점수의 최댓값을 구하는 프로그램을 작성하시오.
문제풀이
사용한 알고리즘 : Greedy, DP
강산님의 글을 참고하여 풀이를 작성하였습니다.
(1) 생각
생각해보면, P_i 는 페널티 느낌으로, P_i 가 클 수록 늦게 풀면 완전 손해입니다.
더 나아가 문제풀이가 t 시간 진행 된 후, a, b 두 문제를 풀어 얻는 점수를 생각해보면
1] a 풀고 b 푸는 경우 얻는 점수 :
M_a-(t+R_a)*P_a + M_b-(t+R_a+R_b)*P_b
2] b 풀고 a 푸는 경우 얻는 점수 :
M_b-(t+R_b)*P_b + M_a-(t+R_b+R_a)*P_a
입니다.
a 먼저 푸는게 이득이려면 1] - 2] > 0 이어야 겠죠?
1] - 2] = R_b*P_a - R_a*P_b > 0 이면 a 먼저 푸는게 이득입니다.
즉 R_a/P_a < R_b/R_a 이면 a 먼저 푸는게 이득입니다.
따라서 Greedy 느낌으로 R/P 가 작은거부터 푸는게 이득일겁니다.
(2) 코드 7~19 , 44
과정(1) 의 생각을 구현하는 struct 를 만들고, 이를 sort 해줍니다. (R/P가 작은게 먼저오게)
(3) 코드 22~34
sort 된 문제들을 차례로 탐색하며 dp 로 푸는 함수를 만듭니다.
'dp[k][t] : k번째 문제, t의 시간 에서 얻을 수 있는 최대 점수' 라고 설정하였습니다.
각 문제를 탐색 할 때
1] 안 풀고 넘기는 경우
2] 풀고 넘기는 경우
2가지 경우가 있겠죠?
안 풀고 넘기면 시간을 안쓰고, 풀고 넘길 경우 시간을 쓰고 점수를 얻겠죠...
문제를 풀 경우는 현재시간 + 문제풀이시간 <= 제한시간 이어야 합니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
using namespace std; | |
typedef long long ll; | |
int N; | |
ll T; | |
struct Node { | |
ll M; | |
ll P; | |
ll R; | |
Node() { | |
M = 0LL; | |
P = 0LL; | |
R = 0LL; | |
} | |
bool operator < (const Node& rhs) const { | |
return R * rhs.P < rhs.R* P; // R/P 가 작은거 우선 | |
} | |
}; | |
Node arr[111111]; | |
ll dp[55][111111]; | |
ll path(int idx, ll time) { | |
if (idx == N) return 0LL; // 다봄 | |
ll& ret = dp[idx][(int)time]; | |
if (ret != -1) return ret; | |
ret = path(idx + 1, time); // 이번꺼 안해봄 | |
if (time + arr[idx].R <= T) // 이번꺼 해보기 | |
ret = max(ret, arr[idx].M - (time + arr[idx].R) * arr[idx].P + path(idx + 1, time + arr[idx].R)); | |
return ret; | |
} | |
int main() {ios_base::sync_with_stdio(false); cout.tie(NULL); cin.tie(NULL); | |
cin >> N >> T; | |
for (int i = 0; i < N; ++i) cin >> arr[i].M; | |
for (int i = 0; i < N; ++i) cin >> arr[i].P; | |
for (int i = 0; i < N; ++i) cin >> arr[i].R; | |
sort(arr, arr + N); | |
memset(dp, -1, sizeof(dp)); | |
cout << path(0, 0LL) << '\n'; | |
return 0; | |
} |
댓글
댓글 쓰기
긴 글 읽어주셔서 감사합니다.
궁금한게 있으시다면 댓글 달아주세요!