1. 문제 링크
https://www.acmicpc.net/problem/1759
1759번: 암호 만들기
첫째 줄에 두 정수 L, C가 주어진다. (3 ≤ L ≤ C ≤ 15) 다음 줄에는 C개의 문자들이 공백으로 구분되어 주어진다. 주어지는 문자들은 알파벳 소문자이며, 중복되는 것은 없다.
www.acmicpc.net
2. 나의 코드
메모리: 14712kb
시간: 136ms
코드 길이: 1402B
설명: 순열을 사용해서 모든 경우의 수를 구한다.
시간복잡도 : O(N!)
하지만 만약 그 전의 알파벳과 비교해 정렬이 되지 않은 문자가 있으면 백트래킹을 한다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static char[] alpha;
static int L, C;
static char[] input;
static boolean[] isSelected;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
L = Integer.parseInt(st.nextToken());
C = Integer.parseInt(st.nextToken());
input = new char[L];
alpha = new char[C];
isSelected = new boolean[C];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < C; i++) {
alpha[i] = st.nextToken().charAt(0);
}
Arrays.sort(alpha);
perm(0);
}
public static void perm(int cnt) {
if (cnt == L) {
if (check()) {
String str = String.valueOf(input);
System.out.println(str);
}
return;
}
for (int i = 0; i < C; i++) {
if (isSelected[i]) {
continue;
}
if (cnt != 0 && alpha[i] - input[cnt - 1] < 0) continue;
input[cnt] = alpha[i];
isSelected[i] = true;
perm(cnt + 1);
isSelected[i] = false;
}
}
public static boolean check() {
int x = 0, y = 0;
for (char c : input) {
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') x++;
else y++;
}
if (x >= 1 && y >= 2) return true;
return false;
}
}
3. 정답 코드
import java.util.Arrays;
import java.util.Scanner;
public class 암호만들기 {
static int L, C;
static char[] data;
public static void main(String[] args) {
Scanner sc = new Scanner("4 6\na t c i s w");
L = sc.nextInt();
C = sc.nextInt();
data = new char[C];
for (int c = 0; c < C; c++) data[c] = sc.next().charAt(0);
Arrays.sort(data);
solve(0, 0, "");
}
static void solve(int cnt, int start, String ans) {
if (cnt == L) {
char[] arr = ans.toCharArray();
int moCnt = 0, jaCnt = 0;
for (char c : arr) {
if (c == 'a' || c == 'i' || c == 'e' || c == 'o' || c == 'u') moCnt++;
else jaCnt++;
}
if (moCnt >= 1 && jaCnt >= 2) System.out.println(ans);
return;
}
for (int i = start; i < C; i++) {
solve(cnt + 1, i + 1, ans + data[i]);
}
}
}
import java.io.*;
import java.util.*;
public class Main {
public static int L, C;
public static char[] list;
public static char[] code;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringBuilder sb = new StringBuilder();
StringTokenizer st = new StringTokenizer(br.readLine());
L = Integer.parseInt(st.nextToken());
C = Integer.parseInt(st.nextToken());
list = new char[C];
code = new char[L];
st = new StringTokenizer(br.readLine());
for (int x = 0; x < C; x++) {
list[x] = st.nextToken().charAt(0);
}
// 정렬
Arrays.sort(list);
makeCode(0,0);
}
public static void makeCode(int x,int idx) {
if (idx == L) {
// 최소 한개의 모음, 최소 2개의 자음인지 확인
if (isValid()) {
System.out.println(code);
}
return;
}
// 아직 길이 L의 코드를 만들지 않았고 글자도 아직 남았다.
for (int i = x; i < C; i++) {
code[idx] = list[i];
makeCode(i+1, idx + 1);
}
}
// 최소 모음 1개, 최소 자음 2개인지 확인
public static boolean isValid() {
int mo = 0;
int ja = 0;
for (char x : code) {
if (x == 'a' || x == 'e' || x == 'i' || x == 'o' || x == 'u') {
mo++;
} else {
ja++;
}
}
if (mo >= 1 && ja >= 2) {
return true;
}
return false;
}
}
4. 배운 점
- 정렬을 한 후 순열을 사용하지 않고 조합을 사용하면 어짜피 뒤에 있는 알파벳이 사전순이라는 것을 알았다. 무의미한 순열을 한 것이다.
'Algorithm > Problem' 카테고리의 다른 글
마법사 상어와 비바라기(BJ_G5_21610) (1) | 2024.02.24 |
---|---|
마법사 상어와 파이어볼(BJ_G4_20056) (1) | 2024.02.24 |
다리 만들기 2(BJ_G1_17472) (0) | 2024.02.22 |
아기 상어(BJ_G3_16236) (0) | 2024.02.21 |
제목(사이트_난이도_문제번호) (0) | 2024.02.21 |