Problem Solving/Baekjoon

[백준/JAVA] 14501 - 퇴사

jihyeon99 2024. 7. 19. 21:59

문제 정보

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

 

문제 

 

문제 해결 과정

완전 탐색 풀이

Ti와 Pi를 살펴보면, 상담기간이 길다고해서 상담금액이 큰 것이 아니었다. 즉, 상담기간과 상담금액은 랜덤하게 주어졌으므로, 그리디와 같은 방법으로는 접근할 수 없고 완전탐색이 필요한 문제이다.

 

각 날짜의 상담을 진행하거나 미진행할때의 모든 경우를 생각해보면, 가능한 경우의 수는 다음과 같다.

1일(상담/미상담) x 2일(상담/미상담) x ... x n일(상담/미상담) = 2^n가지

 

문제에서 n이 최대 15라고 주어졌으므로, 시간복잡도는 O(2^15)이므로 주어진 시간 내에 풀 수 있다.


하지만, 퇴사2와 같은 경우에는 n이 최대 1,500,000이므로 주어진 시간 내에 불가능하다.

그렇다면, 랜덤조건 내에서 시간을 줄일 수 있는 방법이라면 혹시 dp??

 

DP 풀이

dp의 정의를 다음과 같이 두가지 방식으로 정의하고, 각각에 대해 재귀와 반복문을 이용하여 구현해보았다.

  dp[i] : 첫째날부터 i일까지의 최대이익 dp[i] : i일부터 마지막날까지의 최대이익
재귀 X
반복문

 

번 방법 : 재귀 + dp[i]는 i일부터 마지막날까지의 최대이익

class Main {	
	static int solveDp(int day, int n, int[] dp, int[][] schedule) {
		// 종료조건 (상담 가능 날짜 벗어난 경우)
		if(day > n) return 0;
		
		// 이미 계산된 적 있다면 => 재사용
		if(dp[day] != 0) return dp[day];
		
		// 해당 날짜에 상담 진행 o
		int take = 0;
		if(day + schedule[0][day] -1 <= n) {
			take = schedule[1][day] + solveDp(day + schedule[0][day], n, dp, schedule);
		}
		
		// 해당 날짜에 상담 진행 x
		int notTake = solveDp(day+1, n, dp, schedule);
		
		dp[day] = Math.max(take, notTake);
		
		return dp[day];
	}
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int n = Integer.parseInt(br.readLine()); // 남은 날짜
		int[][] schedule = new int[2][n+1]; // 상담 일정표 (0행: 시간, 1행: 비용)
		
		for(int i=1; i<=n; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			schedule[0][i] = Integer.parseInt(st.nextToken()); // 상담시간
			schedule[1][i] = Integer.parseInt(st.nextToken()); // 상담비용
		}
		
		int[] dp = new int[n+1]; // dp[i]: i일부터 마지막날(n)까지의 최대이익
		
		solveDp(1, n, dp, schedule);
		
		System.out.println(dp[1]);
	}
}

 

번 방법 : 반복문 + dp[i]는 첫째날부터 i일까지의 최대이익

class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int n = Integer.parseInt(br.readLine()); // 남은 날짜
		int[][] schedule = new int[2][n+1]; // 상담 일정표 (0행: 시간, 1행: 비용)
		
		for(int i=1; i<=n; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			schedule[0][i] = Integer.parseInt(st.nextToken()); // 상담시간
			schedule[1][i] = Integer.parseInt(st.nextToken()); // 상담비용
		}
		
		int[] dp = new int[n+1]; // dp[i]: 첫째날부터 i일까지의 최대이익
		for(int i=1; i<=n; i++) {
			// 해당 날짜에 상담 진행 o
			if(i + schedule[0][i] -1 <= n) {
				dp[i + schedule[0][i] -1] = Math.max(dp[i + schedule[0][i] -1], dp[i-1] + schedule[1][i]);
			}
			
			// 해당 날짜에 상담 진행 x
			if(i < n) {
				dp[i+1] = Math.max(dp[i+1], dp[i]);
			}
		}
		
		System.out.println(dp[n]);
	}
}

 

번 방법 : 반복문 + dp[i]는 i일부터 마지막날까지의 최대이익

class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int n = Integer.parseInt(br.readLine()); // 남은 날짜
		int[][] schedule = new int[2][n+1]; // 상담 일정표 (0행: 시간, 1행: 비용)
		
		for(int i=1; i<=n; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			schedule[0][i] = Integer.parseInt(st.nextToken()); // 상담시간
			schedule[1][i] = Integer.parseInt(st.nextToken()); // 상담비용
		}
		
		int[] dp = new int[n+2]; // dp[i]: i일부터 마지막날(n)까지의 최대이익
		for(int i=n; i>=1; i--) {
			// 해당 날짜에 상담 진행 o
			int take = 0;
			if(i + schedule[0][i] -1 <= n) {
				take = dp[i + schedule[0][i]] + schedule[1][i];
			}
			
			// 해당 날짜에 상담 진행 x
			int notTake = dp[i+1];
			
			dp[i] = Math.max(take, notTake);
		}
		
		System.out.println(dp[1]);
	}
}

'Problem Solving > Baekjoon' 카테고리의 다른 글

[백준/JAVA] 20926 - 얼음미로  (0) 2024.07.30
[백준/JAVA] 2579 - 계단 오르기  (0) 2024.07.19
[SWEA/JAVA] 8275 - 햄스터  (0) 2024.07.11