백준 2529 - 부등호
Updated:
C++
2529번 - 부등호
문제
여러분은 제시된 k개의 부등호 순서를 만족하는 (k+1)자리의 정수 중에서 최댓값과 최솟값을 찾아야 한다. 앞서 설명한 대로 각 부등호의 앞뒤에 들어가는 숫자는 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }중에서 선택해야 하며 선택된 숫자는 모두 달라야 한다. 문제 출처
접근 방법
0부터 9까지의 수 중에서 (k+1)개 수를 뽑는다.
즉 k가 3이어 부등호가 3개이면 수는 4개이므로, [0, 1, 2, 3] / [0, 1, 2, 4] / [0, 1, 2, 5] … 등등 10개 수 중에서 (k+1)개의 수를 뽑는다.
그 뽑은 수를 가지고 부등호를 비교하여, 만약 모든 수가 주어진 부등호의 조건에 맞으면 그 수들을 연결해 가장 큰 수를 찾는다.
코드
#include <iostream>
#include <vector>
#include <algorithm>
#include <math.h>
#include <string>
using namespace std;
int k, n;
int sel[10];
char sign[9];
bool visited[10];
vector<long long> result;
void DFS(int lv);
void chkSign();
void makeInt();
void print();
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> k;
n = k + 1;
for (int i = 0; i < k; i++)
cin >> sign[i];
DFS(0); //k + 1개의 수를 뽑으며, 이 수를 가지고 부등호를 만족하는 모든 숫자들의 연결을 구한다.
sort(result.begin(), result.end()); //모든 연결된 숫자들을 정렬한다.
string max_num, min_num;
max_num = to_string(result.at(result.size() - 1)); // 정렬 된 수 중, 가장 뒤에 있는 값을 가져온다. 이는 가장 큰 수다.
if (result.at(0) < pow(10, k)) // 가장 작은 수를 가져오는데, 이때 이 수는 제일 앞 자리의 수가 0이므로 제일 앞자리에 0을 붙혀준다.
min_num = "0" + to_string(result.at(0));
else {
min_num = to_string(result.at(0));
}
cout << max_num << "\n";
cout << min_num;
}
void DFS(int lv) {
if (lv == n) { //k + 1개의 수를 뽑는다.
chkSign();
return;
}
for (int i = 0; i < 10; i++) {
if (!visited[i]) {
sel[lv] = i;
visited[i] = true;
DFS(lv + 1);
visited[i] = false;
}
}
}
void print() { //k + 1개의 수가 제대로 뽑혔는지 확인하기 위한 함수.
for (int i = 0; i < n; i++) {
cout << sel[i] << " ";
}
cout << "\n";
}
void chkSign() { //뽑은 수를 가지고 부등호를 비교한다.
bool success = true;
for (int i = 0; i < k; i++) { //부등호의 개수 만큼 반복한다.
char curS = sign[i];
if (curS == '<') { //조건문은 부등호를 적용하였을 때, 틀렸는 지를 확인한다. 만약 '<' 인데 6 < 5 가 되면 틀린 부등호라고 인식한다.
if (sel[i] > sel[i + 1]) {
success = false;
break;
}
}
else {
if (sel[i] < sel[i + 1]) {
success = false;
break;
}
}
}
if (success) { //위의 모든 조건이 통과 되면 올바를 수 조합이므로, 이 수들을 가지고 하나의 수로 만든다.
makeInt();
}
return;
}
void makeInt() { // 각 수들을 10의 자리수에 맞추면서 하나의 큰 수로 만들어준다.
long long num = 0;
num += sel[n-1];
for (int i = 0; i < n - 1; i++) {
num += sel[i] * pow(10 ,(n - i - 1));
}
result.push_back(num);
}
코드 - Java
2021/03/01에 한번 더 풀었다.
이전 코드와 다른 부분은 뽑은 수를 Math.min / Math.max를 통하여 바로바로 갱신해주었다.
import java.util.*;
import java.io.*;
public class Main {
static int n;
static long biggest = 0, smallest = Long.MAX_VALUE; //최대 수인 9876543210은 int로 담을 수 없다.
static char[] sign;
static int[] sel, vis;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = stoi(br.readLine());
sign = new char[n];
sel = new int[n + 1];
vis = new int[10];
StringTokenizer stk = new StringTokenizer(br.readLine());
for(int i = 0; i < n; i++)
sign[i] = stk.nextToken().charAt(0);
DFS(0);
String str;
str = String.valueOf(biggest);
System.out.println(str);
str = String.valueOf(smallest);
if(String.valueOf(smallest).length() == n) {
str = "0" + str;
}
System.out.println(str);
br.close();
return;
}
public static void DFS(int lv) {
if(lv == n + 1) {
if(!Chk())
return;
long comp = 0;
int idx = 0;
for(int i = n; i >= 0; i--) {
comp += sel[idx++] * Math.pow(10, i);
}
biggest = Math.max(comp, biggest);
smallest = Math.min(comp, smallest);
return;
}
for(int i = 0; i < 10; i++) {
if(vis[i] == 0) {
vis[i] = 1;
sel[lv] = i;
DFS(lv + 1);
vis[i] = 0;
}
}
}
public static boolean Chk() {
for(int i = 0; i < n; i++) {
if(sign[i] == '<') {
if(sel[i] > sel[i + 1])
return false;
}
else {
if(sel[i] < sel[i + 1])
return false;
}
}
return true;
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
후기 및 개선할 점
아마도, 4개월 전에 풀었을 때에도 long 형 타입이 발목을 잡은 것 같다.
항상 문제를 풀때 경계 값 테스트를 해야한다는 것을 한번 더 상기시켜준 문제이다.
내가 보통 설정하는 int의 최대 값은 987654321이라는 것을 생각하자.