시간 제한 | 메모리 제한 | 제출 | 정답 | 맞은 사람 | 정답 비율 |
---|---|---|---|---|---|
1 초 | 512 MB | 307 | 147 | 112 | 48.276% |
문제
곧 졸업을 앞둔 민호는 대학교 생활 동안 구매만 해놓고 한 번도 펴보지 않은 전공책에 먼지가 쌓여 있는 것을 보고는, 이 책들을 어떻게 처리해야 할지 고민 중이다. 열심히 고민한 끝에 민호는 결국 전공책을 모두 버리기로 마음먹었다. 하지만 그냥 버리기엔 심심한 민호는 전공책 제목에 있는 글자들을 오려서 단어 만들기 놀이를 하려고 한다. 단어 만들기 놀이는 아래 예시와 같다.
)
)
)
- 1번 책 :
COMPUTERARCHITECTURE
(35,000원) - 2번 책 :
ALGORITHM
(47,000원) - 3번 책 :
NETWORK
(43,000원) - 4번 책 :
OPERATINGSYSTEM
(40,000원)
만약 민호가 만들고 싶은 단어가 ALMIGHTY
라고 하면, 위 4개의 책 중, 1번 책에서 A
를, 2번 책에서 L, M, I, G, H, T
를, 4번 책에서 Y
를 오려내어 원하는 단어를 만들 수 있다. 이때 드는 비용은 1번, 2번, 4번 책 가격의 합인 122,000원
이다.
만약 ANT
라는 단어를 만들고 싶다고 하면, 2번 책에서 A
를, 3번 책에서 N, T
를 오려내어 원하는 단어를 만들 수 있다. 이때 드는 비용은 2번과 3번 책 가격을 합하여 90,000원
이다. 그런데, ANT
라는 단어에서 A
를 2번 책에서 오려내지 않고, 4번 책에 있는 A
를 오려낼 수도 있다. 만약 4번 책에서 A
를 오려냈을 때 드는 비용은 3번과 4번 책 가격을 합하여 83,000원
으로 2번과 3번 책을 고른 비용보다 작다. 하지만, 4번 책에는 ANT
가 모두 포함되어 있으므로, 4번 책만 선택했을 때 드는 비용이 40,000원
이다. 이는 ANT
라는 단어를 만들기 위해서 가장 적은 비용이다.
민호는 여러 개의 전공책들을 나열해 놓고는, 심각한 고민 끝에 전공책 제목에 있는 글자를 오려내어 자신이 원하는 단어를 만들기 위해서는 여러 가지 경우가 있다는 것을 깨달았다. 매우 심심했던 민호는 가장 적은 비용으로 자신이 원하는 단어를 만들려면 어떤 전공책들을 선택해야 하는지 궁금했다. 하지만 일일이 가능한 조합을 만들어 보는 것은 매우 시간 낭비라고 생각한 민호는 컴퓨터공학과답게 프로그램을 만들려고 한다.
민호를 도와 각 전공책의 가격과 제목이 주어졌을 때, 가장 적은 비용으로 민호가 원하는 단어를 만들기 위해서 어떤 전공책을 선택해야 하는지 알아보자.
입력
첫 번째 줄에는 민호가 만들고자 하는 단어를 의미하는 문자열 T (1 ≤ |T| ≤ 10)가 주어진다. T는 항상 대문자이며, |T|는 문자열 T의 길이를 의미한다.
두 번째 줄에는 민호가 가진 전공책의 개수를 의미하는 정수 N (1 ≤ N ≤ 16)이 주어진다.
다음 N개의 각 줄에는 전공책 가격을 의미하는 정수 Ci (10,000 ≤ Ci ≤ 100,000)와 제목을 의미하는 문자열 Wi (1 ≤ |Wi| ≤ 50)가 주어진다. Wi는 항상 대문자이다.
출력
민호가 원하는 단어 T를 만들기 위해서 선택해야 하는 전공책의 가장 적은 가격의 합을 출력한다. 만약 단어를 만들 수 없다면 -1
을 출력한다.
예제 입력 1
ANT
4
35000 COMPUTERARCHITECTURE
47000 ALGORITHM
43000 NETWORK
40000 OPERATINGSYSTEM
예제 출력 1
40000
예제 입력 2
ALMIGHTY
4
35000 COMPUTERARCHITECTURE
47000 ALGORITHM
43000 NETWORK
40000 OPERATINGSYSTEM
예제 출력 2
87000
예제 입력 3
BAKEJOON
3
25000 JAVA
10000 OOP
30000 BINARYCHECK
예제 출력 3
65000
예제 입력 4
JAVA
2
30000 CPLUSPLUS
25000 PYTHON
예제 출력 4
-1
코드
/*
알파벳 배열을 활용한 dfs + 백트래킹 !
가능한 모든 경우를 탐색할 수 있는 이유는 n이 16이하로 넉넉하기 때문이다.
+ bfs , 비트마스킹 으로도 풀 수 있다.
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class p16508 {
static List<Book> books = new ArrayList<>();
static String T;
static int[] count = new int[26];
static int[] select_cnt = new int[26];
static int n, min = Integer.MAX_VALUE;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
T = br.readLine();
int len = T.length();
for (int i = 0; i < len; i++) {
count[T.charAt(i) - 'A']++;
}
n = Integer.parseInt(br.readLine());
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
books.add(new Book(Integer.parseInt(st.nextToken()), st.nextToken()));
}
dfs(0, 0);
System.out.println(min == Integer.MAX_VALUE ? - 1 : min);
}
static void dfs(int index, int total) {
if (index == n) {
// 뽑은 알파벳이 유효하다면 최소값 구한다
if (check()) {
min = Math.min(min, total);
}
return;
}
// dfs 백트래킹으로 모든 경우를 조합한다.
for (int i = 0; i < books.get(index).getTitle().length(); i++) {
select_cnt[books.get(index).getTitle().charAt(i) - 'A']++;
}
dfs(index + 1, total + books.get(index).getPrice());
for (int i = 0; i < books.get(index).getTitle().length(); i++) {
select_cnt[books.get(index).getTitle().charAt(i) - 'A']--;
}
dfs(index + 1, total);
}
static boolean check() {
for (int i = 0; i < 26; i++) {
if (count[i] > select_cnt[i]) {
return false;
}
}
return true;
}
}
class Book {
int price;
String title;
public Book (int price, String title) {
this.price = price;
this.title = title;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
비트마스킹 풀이
import java.util.*;
import java.io.*;
public class Main{
public static void main(String[] args)throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String target = br.readLine();
int t = target.length();
//전공책 수
int n = Integer.parseInt(br.readLine());
String[] title = new String[n];
int[] costs = new int[n];
for(int i = 0; i < n; i++){
String[] book = br.readLine().split(" ");
costs[i] = Integer.parseInt(book[0]);
title[i] = book[1];
}
//total 조합
int total = 1<<n;
int answer = -1;
for (int i = 1; i < total; i++) {
int[] cnt = new int[26];
int costSum =0;
for (int j = 0; j < n; j++) {
//책 선택
if ((i & (1 << j)) > 0) {
String bookT = title[j];
for (int k = 0; k < bookT.length(); k++) {
cnt[bookT.charAt(k) - 'A']++;
}
costSum += costs[j];
}
}
if (check(cnt,target)) {
if(answer == -1)answer=costSum;
else answer = Math.min(answer, costSum);
}
}
System.out.println(answer);
}
public static boolean check(int[] cnt, String target) {
for (int i = 0; i < target.length(); i++) {
if (cnt[target.charAt(i) - 'A'] == 0) return false;
cnt[target.charAt(i) - 'A']--;
}
return true;
}
}
BFS 풀이
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static String target;
static int n;
static Book[] books;
static public void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String input=br.readLine();
StringTokenizer st=new StringTokenizer(input," ");
target=st.nextToken();
st=new StringTokenizer(br.readLine()," ");
n=Integer.parseInt(st.nextToken());
books=new Book[n];
int answer=Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
st=new StringTokenizer(br.readLine()," ");
books[i]=new Book(Integer.parseInt(st.nextToken()),st.nextToken());
}
Arrays.sort(books,(a,b)->a.price-b.price);
for(int i=0;i<n;i++){
String remain=remove(target,books[i].name);
if(!remain.equals(target))
answer=Math.min(answer,bfs(i,books[i].price,remain));
}
if(answer==Integer.MAX_VALUE)
System.out.println(-1);
else
System.out.println(answer);
}
private static int bfs(int index, int price,String remain) {
if(remain.equals("")){
return price;
}
int result=Integer.MAX_VALUE;
for (int i=index+1;i<n;i++){
String next=remove(remain,books[i].name);
if(!next.equals(remain))
result=Math.min(result,bfs(i,price+books[i].price,next));
}
return result;
}
private static String remove(String target, String name) {
StringBuilder sb=new StringBuilder(target);
char[] array=name.toCharArray();
for (int i = 0; i < array.length; i++) {
int index=sb.toString().lastIndexOf(array[i]);
if(index>=0){
sb.deleteCharAt(index);
}
}
return sb.toString();
}
static class Book{
String name;
int price;
public Book(int price,String name) {
this.name = name;
this.price = price;
}
}
}
'알고리즘 > [ Baekjoon ]' 카테고리의 다른 글
[ BOJ ][JAVA][16916] 부분 문자열 (0) | 2021.05.08 |
---|---|
[ BOJ ][JAVA][16637] 괄호 추가하기 (0) | 2021.05.08 |
[ BOJ ][JAVA][16439] 치킨치킨치킨 (0) | 2021.05.08 |
[ BOJ ][JAVA][16400] 소수 화폐 (0) | 2021.05.08 |
[ BOJ ][JAVA][16235] 나무 재테크 (0) | 2021.05.08 |