Algorithm/λ¬Έμ œν’€μ΄

[λ°±μ€€] 2579번 - 계단 였λ₯΄κΈ° (C++)

moaoh 2023. 8. 14. 23:26

 

2579번: 계단 였λ₯΄κΈ°

계단 였λ₯΄κΈ° κ²Œμž„μ€ 계단 μ•„λž˜ μ‹œμž‘μ λΆ€ν„° 계단 κΌ­λŒ€κΈ°μ— μœ„μΉ˜ν•œ λ„μ°©μ κΉŒμ§€ κ°€λŠ” κ²Œμž„μ΄λ‹€. <κ·Έλ¦Ό 1>κ³Ό 같이 각각의 κ³„λ‹¨μ—λŠ” μΌμ •ν•œ μ μˆ˜κ°€ μ“°μ—¬ μžˆλŠ”λ° 계단을 밟으면 κ·Έ 계단에 μ“°μ—¬ μžˆλŠ” 점

www.acmicpc.net

 

문제

계단 였λ₯΄κΈ° κ²Œμž„μ€ 계단 μ•„λž˜ μ‹œμž‘μ λΆ€ν„° 계단 κΌ­λŒ€κΈ°μ— μœ„μΉ˜ν•œ λ„μ°©μ κΉŒμ§€ κ°€λŠ” κ²Œμž„μ΄λ‹€. <κ·Έλ¦Ό 1>κ³Ό 같이 각각의 κ³„λ‹¨μ—λŠ” μΌμ •ν•œ μ μˆ˜κ°€ μ“°μ—¬ μžˆλŠ”λ° 계단을 밟으면 κ·Έ 계단에 μ“°μ—¬ μžˆλŠ” 점수λ₯Ό μ–»κ²Œ λœλ‹€.

<κ·Έλ¦Ό 1>

예λ₯Ό λ“€μ–΄ <κ·Έλ¦Ό 2>와 같이 μ‹œμž‘μ μ—μ„œλΆ€ν„° 첫 번째, 두 번째, λ„€ 번째, μ—¬μ„― 번째 계단을 λ°Ÿμ•„ 도착점에 λ„λ‹¬ν•˜λ©΄ 총 μ μˆ˜λŠ” 10 + 20 + 25 + 20 = 75점이 λœλ‹€.

<κ·Έλ¦Ό 2>

계단 였λ₯΄λŠ” λ°λŠ” λ‹€μŒκ³Ό 같은 κ·œμΉ™μ΄ μžˆλ‹€.

  1. 계단은 ν•œ λ²ˆμ— ν•œ 계단씩 λ˜λŠ” 두 계단씩 였λ₯Ό 수 μžˆλ‹€. 즉, ν•œ 계단을 λ°ŸμœΌλ©΄μ„œ μ΄μ–΄μ„œ λ‹€μŒ κ³„λ‹¨μ΄λ‚˜, λ‹€μŒ λ‹€μŒ κ³„λ‹¨μœΌλ‘œ 였λ₯Ό 수 μžˆλ‹€.
  2. μ—°μ†λœ μ„Έ 개의 계단을 λͺ¨λ‘ λ°Ÿμ•„μ„œλŠ” μ•ˆ λœλ‹€. 단, μ‹œμž‘μ μ€ 계단에 ν¬ν•¨λ˜μ§€ μ•ŠλŠ”λ‹€.
  3. λ§ˆμ§€λ§‰ 도착 계단은 λ°˜λ“œμ‹œ λ°Ÿμ•„μ•Ό ν•œλ‹€.

λ”°λΌμ„œ 첫 번째 계단을 밟고 이어 두 번째 κ³„λ‹¨μ΄λ‚˜, μ„Έ 번째 κ³„λ‹¨μœΌλ‘œ 였λ₯Ό 수 μžˆλ‹€. ν•˜μ§€λ§Œ, 첫 번째 계단을 밟고 이어 λ„€ 번째 κ³„λ‹¨μœΌλ‘œ μ˜¬λΌκ°€κ±°λ‚˜, 첫 번째, 두 번째, μ„Έ 번째 계단을 μ—°μ†ν•΄μ„œ λͺ¨λ‘ λ°Ÿμ„ μˆ˜λŠ” μ—†λ‹€.

각 계단에 μ“°μ—¬ μžˆλŠ” μ μˆ˜κ°€ μ£Όμ–΄μ§ˆ λ•Œ 이 κ²Œμž„μ—μ„œ 얻을 수 μžˆλŠ” 총 점수의 μ΅œλŒ“κ°’μ„ κ΅¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.

 

 

 

μž…λ ₯

μž…λ ₯의 첫째 쀄에 κ³„λ‹¨μ˜ κ°œμˆ˜κ°€ μ£Όμ–΄μ§„λ‹€.

λ‘˜μ§Έ 쀄뢀터 ν•œ 쀄에 ν•˜λ‚˜μ”© 제일 μ•„λž˜μ— 놓인 계단뢀터 μˆœμ„œλŒ€λ‘œ 각 계단에 μ“°μ—¬ μžˆλŠ” μ μˆ˜κ°€ μ£Όμ–΄μ§„λ‹€. κ³„λ‹¨μ˜ κ°œμˆ˜λŠ” 300μ΄ν•˜μ˜ μžμ—°μˆ˜μ΄κ³ , 계단에 μ“°μ—¬ μžˆλŠ” μ μˆ˜λŠ” 10,000μ΄ν•˜μ˜ μžμ—°μˆ˜μ΄λ‹€.

 

 

 

좜λ ₯

첫째 쀄에 계단 였λ₯΄κΈ° κ²Œμž„μ—μ„œ 얻을 수 μžˆλŠ” 총 점수의 μ΅œλŒ“κ°’μ„ 좜λ ₯ν•œλ‹€.

 

 

 

풀이과정

λ¬Έμ œμ—μ„œ μš”κ΅¬ν•˜λŠ” 사항은 μ•„λž˜μ™€ κ°™λ‹€.

  1. 계단은 ν•œλ²ˆμ— 1개 ν˜Ήμ€ 2개
  2. μ—°μ†μœΌλ‘œ μ„Έκ°œμ˜ 계단은 λΆˆκ°€λŠ₯
  3. λ§ˆμ§€λ§‰ 도착 계단은 λ°˜λ“œμ‹œ λ°Ÿμ•„μ•Όν•œλ‹€

μœ„μ™€ 같은 쑰건듀 3κ°€μ§€λ₯Ό μ§€ν‚€κ³  λ§ˆμ§€λ§‰ κ³„λ‹¨μ—μ„œ 얻을 수 μžˆλŠ” 점수의 μ΅œλŒ€κ°’μ„ 좜λ ₯ν•˜λ©΄ λ˜λŠ” ν˜•μ‹μ— λ¬Έμ œμ˜€μ—ˆλ‹€.

ν•΄λ‹Ή 문제의 풀이λ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ μ–΄λ–»κ²Œ 접근을 ν•΄μ•Όν• κΉŒ 고민을 ν•˜λ‹€κ°€ 문득 의문점이 λ“€μ—ˆλ‹€.

dpλŠ” 크게 2κ°€μ§€ λ°©λ²•μœΌλ‘œ 문제λ₯Ό ν’€ 수 μžˆλ‹€κ³  μƒκ°ν•œλ‹€.

  1. 과거의 κ°’μœΌλ‘œ ν˜„μž¬μ˜ 값을 κ΅¬μ„±ν•˜λŠ” 방식.
    "dp[i] = dp[i - 2] + list[i]"
    처럼 i의 값을 κ΅¬ν•˜κΈ° μœ„ν•΄μ„œ μ΄μ „μ˜ 값듀을 κ°€μ Έμ˜€λŠ” 방식. 
  2. ν˜„μž¬μ˜ κ°’μœΌλ‘œ 미래λ₯Ό κ΅¬μ„±ν•˜λŠ” 방식.
    "dp[i + 2] = dp[i] + list[i + 2]" 처럼 i + 2의 값을 κ΅¬ν•˜κΈ°μœ„ν•΄ ν˜„μž¬μ˜ κ°’μœΌλ‘œ 미래의 값을 μ§€μ •ν•΄μ£ΌλŠ” 방식.

μœ„μ™€ 같은 λ°©μ‹μœΌλ‘œ μ ‘κ·Όν•  수 μžˆλ‹€κ³  생각을 ν•˜λŠ”λ° 1번의 λ°©λ²•μ΄λ‚˜ 2번의 λ°©λ²•μ΄λ‚˜ λͺ¨λ‘ μ½”λ“œκ°€ 진행이 λ˜λ‹€λ³΄λ©΄

같은 결과값을 λ„μΆœν•΄ λ‚΄κΈ°λ•Œλ¬Έμ— 두가지 방법 λͺ¨λ‘λ₯Ό μ‚¬μš©ν•΄μ„œ ν’€ 수 μžˆμ§€μ•Šμ„κΉŒ? λΌλŠ” 생각이 문득 λ“€μ—ˆλ‹€.

κ·Έλž˜μ„œ 2번의 방법을 μ‚¬μš©ν•΄μ„œ 문제의 접근을 ν•΄λ³΄μ•˜λ‹€.

 

#include <iostream>
#include <algorithm>

// 계단은 ν•œλ²ˆμ— 1개 ν˜Ήμ€ 2개
// μ—°μ†μœΌλ‘œ μ„Έκ°œμ˜ 계단은 λΆˆκ°€λŠ₯
// λ§ˆμ§€λ§‰ 도착 계단은 λ°˜λ“œμ‹œ λ°Ÿμ•„μ•Όν•œλ‹€.
int		main(void)
{
	int n;
	int	dp[303] = {0}, stairs[303] = {0}, counts[303] = {0};

	std::cin >> n;
	for (int i = 1; i <= n; i++)
		std::cin >> stairs[i];
	for (int i = 0; i <= n; i++) {
		if (dp[i] == 0) dp[i] = stairs[i];
		if (i + 2 < n + 1) {
			dp[i + 2] = dp[i] + stairs[i + 2];
			counts[i + 2] = 1;
		}
		if (i + 1 < n + 1 && counts[i] + 1 < 3) {
			if (i + counts[i] + 1 < n || i + 1 == n) {
				if (dp[i + 1] < dp[i] + stairs[i + 1]) {
					dp[i + 1] = dp[i] + stairs[i + 1];
					counts[i + 1] = counts[i] + 1;
				}
			}
		}
	}

	std::cout << dp[n];

	return (0);
}

κ·Έκ²ƒμ˜ 풀이λ₯Ό μ§„ν–‰ν–ˆλ˜ μ½”λ“œκ°€ μœ„μ™€ κ°™λ‹€.

countsλΌλŠ” λ°°μ—΄λ‘œ λͺ‡λ²ˆμ—°μ†μœΌλ‘œ ν•œμΉΈμœΌλ‘œ μ™”λŠ”μ§€ ν™•μΈν•˜κ³ , 3번 μ—°μ†μœΌλ‘œ ν•œμΉΈμ„ 갈 경우λ₯Ό 미리 방지해버린닀.

μœ„μ˜ μ½”λ“œλ₯Ό λ°”νƒ•μœΌλ‘œ 예제λ₯Ό μ§„ν–‰ν•  κ²½μš°μ—λŠ” μ˜³μ€ 좜λ ₯값이 λ‚˜μ˜€λŠ”κ²ƒμ„ 확인할 수 μžˆμ—ˆλŠ”λ° μ •μž‘ μ œμΆœμ„ ν•΄λ³΄λ‹ˆ

2번 ν’€μ΄λ°©μ‹μ˜ κ²°κ³Ό

λΌλŠ” 값이 λ‚˜μ˜€λŠ” 것을 확인 ν•  수 μžˆμ—ˆλ‹€. κ·Έλž˜μ„œ 무엇이 λ¬Έμ œμΈκ°€λ₯Ό μ°Ύμ•„λ³΄λ‹ˆ μ•„λž˜μ™€ 같은 λ°˜λ‘€λ₯Ό 찾을 수 μžˆμ—ˆλ‹€.

3
40
50
60

answer = 110

μœ„μ— 예제의 κ²½μš°μ—λŠ” 2번째 계단을 κ°€κ³  1칸을 λ›°μ–΄ 3번째 계단에 λ„λ‹¬ν•΄μ„œ 110μ΄λΌλŠ” 결과값을 λ‚΄μ•Όλ§Œν•˜μ§€λ§Œ

μœ„μ™€ 같은 μ½”λ“œμ˜ κ²½μš°μ—λŠ” κ°’μ˜ λŒ€μ†Œλ₯Ό λΉ„κ΅ν•΄μ„œ counts의 κ°’κ³Ό 상관없이 큰값이 μš°μ„ μ μœΌλ‘œ μ νžˆκΈ°λ•Œλ¬Έμ—
μ΅œμ’…μ μœΌλ‘œ 110μ΄λΌλŠ” 결과값에 도달할 수 μ—†μ—ˆλ‹€.

( 3번 쑰건을 λ°”νƒ•μœΌλ‘œ 사전에 미리 μ €μ§€λ₯Ό 해도 λ‹€λ₯Έ μ˜ˆμ œμ—μ„œ ν‹€λ €λ²„λ¦¬λŠ” 일이 μƒκ²Όμ—ˆλ‹€. )

 

μœ„μ—μ„œ ν‹€λ¦° λ‚΄μš©μœΌλ‘œ 생각을 ν•΄λ³΄λ‹ˆ 1번 풀이 방식 (과거의 κ°’μœΌλ‘œ ν˜„μž¬μ˜ 값을 κ΅¬μ„±ν•˜λŠ” 방식.) 으둜 진행을 ν–ˆμœΌλ©΄ 과거의 값을 κΈ°μ€€μœΌλ‘œ ν˜„μž¬μ˜ 값을 κ΅¬μ„±ν•˜λ‹€λ³΄λ‹ˆ 쑰금 더 λ°˜λ‘€λ₯Ό μ‹ κ²½ μ•ˆμ“°κ³  μ½”λ“œ 풀이가 κ°€λŠ₯ν•  κ±° 같은데
2번 풀이 방식 (ν˜„μž¬μ˜ κ°’μœΌλ‘œ 미래λ₯Ό κ΅¬μ„±ν•˜λŠ” 방식.)을 μ‚¬μš©ν•˜λ‹€λ³΄λ‹ˆ μ‹ κ²½μ¨μ•Όν•˜λŠ” λ°˜λ‘€κ°€ λ„ˆλ¬΄ λ§Žμ•„μ‘Œμ—ˆλ‹€.

κ·Έλž˜μ„œ κ²°λ‘ μ μœΌλ‘œλŠ” κ³„λ‹¨μ˜€λ₯΄κΈ° 같이 "μ—°μ†μœΌλ‘œ μ„Έκ°œμ˜ 계단은 λΆˆκ°€λŠ₯" μ‹μ˜ 쑰건이 κ±Έλ €μžˆλŠ” dp 문제의 κ²½μš°μ—λŠ”
1번 풀이 방식을 μ‚¬μš©ν•˜λŠ” 것이 훨씬 μ½”λ“œκ°€ κ°„λ‹¨ν•˜κ³  νŽΈν•΄μ§„λ‹€λŠ” 사싀을 확인 ν•  수 μžˆμ—ˆλ‹€.

 

 

1번 풀이 λ°©μ‹μ˜ 해석은 λ‹€μŒκ³Ό κ°™λ‹€.

λͺ¨λ“  λ§ˆμ§€λ§‰ κ³„λ‹¨κΉŒμ§€ λ„λ‹¬ν•˜λŠ” 방법은

  1. 계단은 ν•œλ²ˆμ— 1개 ν˜Ήμ€ 2개
  2. μ—°μ†μœΌλ‘œ μ„Έκ°œμ˜ 계단은 λΆˆκ°€λŠ₯
  3. λ§ˆμ§€λ§‰ 도착 계단은 λ°˜λ“œμ‹œ λ°Ÿμ•„μ•Όν•œλ‹€

 μ΄λΌλŠ” 쑰건으둜 인해 nλ²ˆκΉŒμ§€ 계단에 λ„λ‹¬ν•˜λŠ” 방법은

2κ°€μ§€ λ°©λ²•μœΌλ‘œλ§Œ 도달이 κ°€λŠ₯ν•˜λ‹€. κ·Έ μ΄μ™Έμ˜ 방법듀은 κ·œμΉ™μ˜ μ–΄κΈ‹λ‚˜λŠ” 도착 λ°©λ²•μ΄λ―€λ‘œ κ°€λŠ₯ν•˜μ§€μ•Šλ‹€.

κ·Έλž˜μ„œ μœ„μ˜ 방법을 μ ν™”μ‹μœΌλ‘œ 정리λ₯Ό ν•΄λ³΄μžλ©΄

1번째

dp[n] = stairs[i] + stairs[i - 1] + dp[i - 3]

2번째

dp[n] = stairs[i] + dp[i - 2]

μ΄λ ‡κ²Œ 2개둜 λ‚˜λˆ„μ–΄μ§€κ²Œ λœλ‹€. κ·Έλž˜μ„œ μœ„μ˜ 쑰건듀을 λ°”νƒ•μœΌλ‘œ λ„λ‹¬ν•˜λŠ” λ°©λ²•μžμ²΄κ°€ μ •ν•΄μ ΈμžˆμœΌλ‹ˆ 계단을 λͺ‡λ²ˆλ°Ÿμ•„κ°€λ©΄μ„œ μ™”λŠ”μ§€λ₯Ό

μƒκ°ν•˜μ§€μ•Šκ³  문제 풀이가 κ°€λŠ₯ν•΄μ§€κ²Œλœλ‹€.

code

#include <iostream>
#include <algorithm>

// 계단은 ν•œλ²ˆμ— 1개 ν˜Ήμ€ 2개
// μ—°μ†μœΌλ‘œ μ„Έκ°œμ˜ 계단은 λΆˆκ°€λŠ₯
// λ§ˆμ§€λ§‰ 도착 계단은 λ°˜λ“œμ‹œ λ°Ÿμ•„μ•Όν•œλ‹€.
int		main(void)
{
	int n;
	int	dp[303] = {0}, stairs[303] = {0};

	std::cin >> n;
	for (int i = 1; i <= n; i++)
		std::cin >> stairs[i];
	dp[1] = stairs[1];
	dp[2] = stairs[1] + stairs[2];
	dp[3] = std::max(stairs[1] + stairs[3], stairs[2] + stairs[3]);
	for (int i = 3; i <= n; i++) {
		dp[i] = std::max(stairs[i] + dp[i - 2], stairs[i] + stairs[i-1] + dp[i-3]);
	}
	for (int i = 1; i <= n; i++) {
		std::cout << dp[i] << " ";
	}
	std::cout << dp[n];

	return (0);
}

 

ν›„κΈ°

dp 문제λ₯Ό 보고 μ–΄λ–»κ²Œ 접근을 ν•΄μ•Όν• μ§€ ν™•μ‹€ν•˜κ²Œ μ•Œκ²Œ λ˜λŠ” λ¬Έμ œμ˜€λ˜ κ±° κ°™λ‹€.

덕뢄에 많이 배우고 μ„±μž₯ν–ˆλ‹€.