[백준 3687번 C/C++] 성냥개비
[백준 3687번 C/C++] 성냥개비

https://www.acmicpc.net/problem/3687
3687번: 성냥개비
각 테스트 케이스에 대해서 입력으로 주어진 성냥개비를 모두 사용해서 만들 수 있는 가장 작은 수와 가장 큰 수를 출력한다. 두 숫자는 모두 양수이어야 하고, 숫자는 0으로 시작할 수 없다.
www.acmicpc.net
해결전략
구현
동적계획법 Dynamic Programming, DP
정답코드
#include <iostream> #include <vector> #include <string> using namespace std; int t; // 테스트 케이스의 개수 int n; // 성냥개비의 개수 // int num[10] = { 2, 5, 5, 4, 5, 6, 3, 7, 6, 6 }; // 각 숫자를 만드는데 필요한 성냥개비의 개수 string MinNum(int x){ // 기본적으로 성냥개비 2~13개로 만들 수 있는 가장 작은 숫자들을 직접 반환 if (x == 2) return "1"; else if (x == 3) return "7"; else if (x == 4) return "4"; else if (x == 5) return "2"; else if (x == 6) return "6"; else if (x == 7) return "8"; else if (x == 8) return "10"; else if (x == 9) return "18"; else if (x == 10) return "22"; else if (x == 11) return "20"; else if (x == 12) return "28"; else if (x == 13) return "68"; // 성냥개비가 14개 이상인 경우 int a = x / 7; // 7개짜리 숫자(8)를 최대한 많이 만들기 int b = x % 7; // 나머지 성냥개비 개수 string minNum = ""; if (b == 0) { while (a--) { minNum = minNum + "8"; // 나머지가 없으면 8만으로 구성 } } else { // 나머지가 있을 경우, 최소 숫자를 만들기 위한 로직 a--; if (b == 1) { while (a--) { minNum = minNum + "8"; } minNum = "10" + minNum; // 나머지가 1개일 때 } else if (b == 2) { while (a--) { minNum = minNum + "8"; } minNum = "18" + minNum; // 나머지가 2개일 때 } else if (b == 3) { a--; while (a--) { minNum = minNum + "8"; } minNum = "200" + minNum; // 나머지가 3개일 때, 특별한 케이스 처리 } else if (b == 4) { while (a--) { minNum = minNum + "8"; } minNum = "20" + minNum; // 나머지가 4개일 때 } else if (b == 5) { while (a--) { minNum = minNum + "8"; } minNum = "28" + minNum; // 나머지가 5개일 때 } else if (b == 6) { while (a--) { minNum = minNum + "8"; } minNum = "68" + minNum; // 나머지가 6개일 때 } } return minNum; } string MaxNum(int x){ if (x == 2) return "1"; else if (x == 3) return "7"; int a = x / 2; string maxNum = ""; if (x % 2 == 0) { while (a--){ maxNum = maxNum + "1"; } } else { // x % 2 == 1 a--; while (a--) { maxNum = maxNum + "1"; } maxNum = "7" + maxNum; } return maxNum; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> t; while (t--) { cin >> n; cout << MinNum(n) << " " << MaxNum(n) << "\n"; } return 0; }
다른 방식의 풀이: 동적계획법 (Dynamic Programming, DP)
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; // 성냥개비를 사용하여 만들 수 있는 숫자들의 배열 // index: 성냥개비 수, value: 해당 성냥개비 수로 만들 수 있는 최소 숫자 vector<string> dp(101, "0"); void init() // 성냥개비를 사용하여 만들 수 있는 숫자들 초기화 { // 각 숫자를 만드는 데 필요한 성냥개비의 최소 개수 dp[2] = "1"; // 1 dp[3] = "7"; // 7 dp[4] = "4"; // 4 dp[5] = "2"; // 2 dp[6] = "6"; // 0 또는 6, 하지만 6을 사용하는 것이 더 낫다. dp[7] = "8"; // 8 dp[8] = "10"; // 10이 최소 // 9개 이상의 성냥개비를 사용하는 경우, 7개 또는 2개 성냥개비를 사용하는 숫자의 조합으로 해결 } void findMinNum() // 주어진 성냥개비의 개수로 만들 수 있는 가장 작은 숫자를 찾는 함수 { for(int i = 9; i <= 100; ++i) { for(int j = 2; j <= 7; ++j) { string nextNum = dp[i-j] + (j == 6 ? "0" : dp[j]); if(dp[i] == "0" || dp[i] > nextNum) { dp[i] = nextNum; } } } } string MinNum(int n) { return dp[n]; } string MaxNum(int n) { if(n % 2 == 1) return "7" + string(n / 2 - 1, '1'); else return string(n / 2, '1'); } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t, n; cin >> t; init(); findMinNum(); while(t--) { cin >> n; cout << MinNum(n) << " " << MaxNum(n) << "\n"; } return 0; }
주어진 성냥개비의 개수를 사용하여 만들 수 있는 가장 작은 숫자를 효율적으로 찾는 데 초점을 맞춥니다.
init 함수에서 성냥개비 2개부터 8개까지 만들 수 있는 최소 숫자들을 초기화한 후, findMinNum 함수에서 9개 이상의 성냥개비를 사용할 때 만들 수 있는 최소 숫자를 찾는다.
가장 큰 숫자를 찾는 방법은 주어진 성냥개비로 가능한 한 많이 '1'을 만드는 것이다(홀수 개일 경우 첫 번째 숫자를 '7'(3개의 성냥개비 필요)로 만들어 나머지를 '1'로 채운다).
다른 방식의 풀이: 동적계획법 (Dynamic Programming, DP)
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; // 성냥개비로 만들 수 있는 숫자별 필요한 성냥개비 수 (0은 제외) // 0은 사용되지 않지만, 인덱스를 맞추기 위해 포함 int matchsticks[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6}; string MinNum(int n) { if(n == 2) return "1"; // 예외 처리: 2개로 만들 수 있는 최소 숫자는 1 // dp[i]는 i개의 성냥개비로 만들 수 있는 최소 숫자다. // INT_MAX로 초기화하여, 아직 계산되지 않았거나 불가능한 경우를 파악한다. vector<int> dp(n+1, INT_MAX); // dp[i]: i개의 성냥개비로 만들 수 있는 최소 숫자 dp[0] = 0; // 0개의 성냥개비는 0을 의미 for(int i = 0; i <= n; ++i) { // 모든 성냥개비 수에 대해, 가능한 모든 숫자를 만든다. for(int num = 1; num < 10; ++num) { // 0은 성냥개비 6개가 필요하므로 여기서는 고려하지 않는다. if(i - matchsticks[num] >= 0) { // 현재 성냥개비 수에서 num을 만들 수 있다면, dp[i] = min(dp[i], dp[i - matchsticks[num]] + 1); // 현재의 최소값과 비교하여 더 작은 값을 선택. } } } string result = ""; for(int i = n; i > 0; ) { // dp를 사용하여 만들 수 있는 최소 숫자를 거꾸로 추적 for(int num = 1; num < 10; ++num) { if(i - matchsticks[num] >= 0 && dp[i] == dp[i - matchsticks[num]] + 1) { // 만약 num 숫자를 만드는 것이 현재 최소값을 만드는데 기여했다면, result += to_string(num); // 결과 문자열에 해당 숫자를 추가 i -= matchsticks[num]; // 사용된 성냥개비 수만큼 빼준다. break; // 다음 숫자로 넘어감. } } } return result; } string MaxNum(int n) // 주어진 성냥개비의 개수로 만들 수 있는 가장 큰 숫자를 반환하는 함수 { string result = ""; if(n % 2 == 1) { // 홀수인 경우 result += "7"; // 7은 3개의 성냥개비가 필요하며, 가장 큰 한 자리 숫자 n -= 3; } while(n > 0) { result += "1"; // 1은 2개의 성냥개비가 필요하며, 나머지를 모두 1로 채움 n -= 2; } return result; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t, n; cin >> t; while(t--) { cin >> n; cout << MinNum(n) << " " << MaxNum(n) << "\n"; } return 0; }
'⭐ 코딩테스트 > 백준' 카테고리의 다른 글
[백준 6087번 C/C++] 레이저 통신 (0) | 2024.04.16 |
---|---|
[백준 2589번 C/C++] 보물선 (0) | 2024.04.15 |
[백준 14890번 C/C++] 경사로 (0) | 2024.04.13 |
[백준 8980번 C/C++] 택배 (0) | 2024.04.10 |
[백준 24337번 C/C++] 가희와 탑 (0) | 2024.04.09 |
댓글
이 글 공유하기
다른 글
-
[백준 6087번 C/C++] 레이저 통신
[백준 6087번 C/C++] 레이저 통신
2024.04.16 -
[백준 2589번 C/C++] 보물선
[백준 2589번 C/C++] 보물선
2024.04.15 -
[백준 14890번 C/C++] 경사로
[백준 14890번 C/C++] 경사로
2024.04.13 -
[백준 8980번 C/C++] 택배
[백준 8980번 C/C++] 택배
2024.04.10
댓글을 사용할 수 없습니다.