2019. 12. 22. 16:57ㆍ[개발] 지식/알고리즘 문제풀이
문제 정보
문제 ID: STRJOIN
시간: 1000ms
제한메모리: 65536kb
문제
프로그래밍 언어 C 의 큰 문제점 중 하나는 언어 차원에서 문자열 변수형을 지원하지 않는다는 것입니다. C 에서는 문자 배열로 문자열을 표현하되 \0 (NULL) 로 문자열의 끝을 지정하는데, 이래서는 문자열의 길이를 쉽게 알 수 있는 방법이 없기 때문에 여러 가지 문제가 발생하게 됩니다.
void strcat(char* dest, const char* src) {
// dest 의 마지막 위치를 찾는다
while(*dest) ++dest;
// src 를 한 글자씩 dest 에 옮겨 붙인다
while(*src) *(dest++) = *(src++);
// 문자열의 끝을 알리는 \0 을 추가한다
*dest = 0;
}
이런 문제 중 하나로 문자열을 조작하는 함수들의 동작 시간이 불필요하게 커진다는 것이 있습니다. 앞에 주어진 함수 strcat() 은 문자열 dest 뒤에 src 를 붙이는 함수인데, 실행 과정에서 반복문을 두 문자열의 길이를 합한 만큼 수행해야 합니다. 이 함수를 사용해 두 개의 문자열을 합치는 비용은 두 문자열의 길이의 합이라고 합시다.
이 함수를 이용해 n 개의 문자열을 순서와 상관없이 합쳐서 한 개의 문자열로 만들고 싶습니다. 순서가 상관 없다는 말은 {al,go,spot} 을 spotalgo 로 합치든 alspotgo 로 합치든 상관 없다는 의미입니다. 그러나 문자열을 합치는 순서에 따라 전체 비용이 달라질 수 있습니다. 예를 들어 먼저 al 과 go 를 합치고 (2+2=4), 이것을 spot 과 합치면 (4+4=8) 총 12 의 비용이 들지만 al 과 spot 을 합치고 (2+4=6) 이것을 다시 go 에 합치면 (6+2=8) 총 14 의 비용이 필요합니다.
n 개의 문자열들의 길이가 주어질 때 필요한 최소 비용을 찾는 프로그램을 작성하세요.
입력
입력의 첫 줄에는 테스트 케이스의 수 c (c <= 50) 가 주어집니다. 각 테스트 케이스의 첫 줄에는 문자열의 수 n (1 <= n <= 100) 이 주어지며, 다음 줄에는 n 개의 정수로 각 문자열의 길이가 주어집니다. 각 문자열의 길이는 1,000 이하의 자연수입니다.
출력
각 테스트 케이스마다 한 줄에 모든 문자열을 합칠 때 필요한 최소 비용을 출력합니다.
예제 입력
3
3
2 2 4
5
3 1 3 4 1
8
1 1 1 1 1 1 1 2
예제 출력
12
26
27
정답소스
package apss;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
public class StrJoin {
public static int N;
public static int arr[];
public static int result;
public static void main(String[] args) throws NumberFormatException, IOException {
// TODO Auto-generated method stub
System.setIn(new FileInputStream("/Users/projooni/sample_input.txt"));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int T = Integer.parseInt(br.readLine());
for(int tc=1; tc<=T; tc++) {
N = Integer.parseInt(br.readLine());
arr = new int[N];
StringTokenizer st = new StringTokenizer(br.readLine());
for(int i=0; i<N; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
result = 0;
getMinStrJoinCost();
bw.flush();
bw.write(result + "\n");
}
bw.close();
}
public static void getMinStrJoinCost() {
PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
for(int i=0; i<N; i++) {
pq.add(arr[i]);
}
while(!pq.isEmpty()) {
int a = pq.poll();
int b = pq.isEmpty() ? 0 : pq.poll();
int joinCost = a+b;
result += joinCost;
if(!pq.isEmpty()) {
pq.add(joinCost);
}
}
}
}
풀이
책의 풀이를 보고 풀었지만, 풀이 자체는 간단하다.
우선순위 큐에 담아서 가장 작은것들 2개를 뽑아 합산하면 된다.
다만 저 단순한 풀이에 접근하는게 쉽진 않은 것 같다.
일단 문제를 보고 직관적으로 판단하기 위해 그림을 그리던 트리를 그리던 어떻게든 표현을 해야 접근법을 얻을 수 있는 것 같다.
'[개발] 지식 > 알고리즘 문제풀이' 카테고리의 다른 글
[APSS][알고스팟] 알러지가 심한 친구들 (ALLERGY) (0) | 2020.01.05 |
---|---|
[APSS][알고스팟] 게임판덮기2 (BOARDCOVER2) (0) | 2020.01.04 |
[알고스팟] 도시락 데우기 (LUNCHBOX) (0) | 2019.07.20 |
[알고스팟] 두니발 박사의 탈옥 (NUMB3RS) (0) | 2019.06.07 |
[알고스팟] 폴리오미노(POLY) (0) | 2019.05.23 |