[코딩테스트] 브루트 포스(재귀)
reference : 2021 코딩테스트 기초(최백준) 강의를 공부하며 정리한 내용입니다.
1,2,3 더하기 (9095번)
https://www.acmicpc.net/problem/9095
문제
1부터 N까지 자연수 중에서 M개를 고른 수열을 모두 구하는 문제(중복선택 가능)
입력
테스트 케이스의 개수 T, (0 ≤ N ≤ 10)
출력
각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 출력한다.
풀이
- 최대 방법의 개수 3^10=59049
- 재귀 : 기준을 정한다(위치=사용한 갯수=count), 기준이 바뀔때 변하는 값을 함수 인자로(합이 변함=sum)
- 다음 경우 호출(하나의 함수가 다른 함수 호출할 때 어떻게 호출할 수 있는지, 각각 값이 어떻게 변하는지. 1을 사용/2를 사용/3을 사용)
- 정답을 찾은 경우(sum==n)
- 불가능한 경우(문제의 조건을 위배, 절대로 답을 구할 수 없음. sum>n)
import java.util.*;
public class Main {
static int num;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
for(int i=0; i<t; i++) {
int n = sc.nextInt();
go(n,0,0);
System.out.println(num);
num=0;
}
}
private static void go(int n, int count, int sum) {
if(sum>n)
return;
if(sum==n)
num++;
for(int i=1; i<=3; i++) {
go(n,count+1,sum+i);
}
}
}
-> count는 지워도 됨. 브루트포스3 할 때 다른 풀이 찾으면서 재귀 코드 보고 어렵다했던 문제인데 직접 재귀로 풀었다! 신남!
1,2,3 더하기 (1759번)
https://www.acmicpc.net/problem/1759
문제
- 암호는 서로 다른 L개의 알파벳 소문자들로 구성되며 최소 한 개의 모음과 최소 두 개의 자음으로 구성
- 암호를 이루는 알파벳이 암호에서 증가하는 순서로 배열
- 암호로 사용할 수 있는 문자의 종류 C가지
- 가능성 있는 암호를 모두 구하는 문제
입력
두 정수 L, C (3 ≤ L ≤ C ≤ 15) C개의 문자들이 공백으로 구분되어 주어진다. 주어지는 문자들은 알파벳 소문자이며, 중복되는 것은 없다.
출력
각 줄에 하나씩, 사전식으로 가능성 있는 암호를 모두 출력한다.
풀이
- N과 M 2와 유사. 증가하는 순서로 배열, 중복x, 최소 한 개의 모음+두개의 자음
- 시간복잡도 O(2^15) = 32768
- 알파벳을 정렬, 몇 번째 알파벳인지 index, 만든 암호 password
- 다음 경우 호출(알파벳을 사용한다)
- alpha[i], i->i+1, password -> password+alpha[i]
- go(n, alpha, password+alpha[i], i+1)
- 알파벳을 사용하지 않는 경우(i -> i+1) go(n, alpha, password, i+1)
- 정답을 찾은 경우 password 길이 == n, 최소 한개 모음 + 두개 자음
- 불가능한 경우 index >= alpha 크기
import java.util.*;
public class Main {
static String password;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int l = sc.nextInt();
int c = sc.nextInt();
char al[] = new char[c];
for(int i=0; i<c; i++) {
al[i] = sc.next().charAt(0);
}
Arrays.sort(al);
go(l,al,"",0);
}
private static void go(int l, char[] al, String password, int i) {
if(password.length()==l) {
if(check(password))
System.out.println(password);
return;
}
if(i>=al.length)
return;
go(l, al, password+al[i], i+1);
go(l, al, password, i+1);
}
private static boolean check(String password) {
int ja = 0;
int mo = 0;
for(char x : password.toCharArray()) {
if(x=='a'||x=='e'||x=='i'||x=='o'||x=='u')
mo++;
else
ja++;
}
if(ja>=2 && mo >= 1)
return true;
else
return false;
}
}
- 시간복잡도 O(2^C x L)
퇴사 (14501번)
https://www.acmicpc.net/problem/14501
문제
- N+1일이 되는 날 퇴사를 하려 한다(1 ≤ N ≤ 15)
- 남은 N일 동안 최대한 많은 상담을 하려고 한다
- 하루에 하나의 상담을 할 수 있고
- i일에 상담을 하면 T[i]일이 걸리고 P[i]원을 번다
입력
첫째 줄에 N (1 ≤ N ≤ 15)이 주어진다.
둘째 줄부터 N개의 줄에 Ti와 Pi가 공백으로 구분되어서 주어지며, 1일부터 N일까지 순서대로 주어진다. (1 ≤ Ti ≤ 5, 1 ≤ Pi ≤ 1,000)
출력
첫째 줄에 백준이가 얻을 수 있는 최대 이익을 출력한다.
풀이
- 날짜 : 기준(상담을 한다, 안 한다) -> 변하는 것 : 날짜, 수입 go(day,sum)
- sum : day-1 일까지 수익
- 다음 경우
- 상담을 한다 go(day+T[ day ] , sum+p[ day ])
- 상담을 안한다 go(day+1,sum)
- 정답을 찾은 경우 day==n+1
- 불가능한 경우 day > n+1
import java.util.*;
public class Main {
static int n;
static int[] t;
static int[] p;
static int ans = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
t = new int[n];
p = new int[n];
for(int i=0; i<n; i++) {
t[i] = sc.nextInt();
p[i] = sc.nextInt();
}
go(0,0);
System.out.println(ans);
}
private static void go(int day, int sum) {
if(day==n) {
if(ans<sum)
ans=sum;
return;
}
if(day>n)
return;
go(day+1,sum);
go(day+t[day],sum+p[day]);
}
}
- 시간 복잡도 O(2ⁿ)
댓글남기기