카카오배 양궁대회가 열렸습니다.
라이언
은 저번 카카오배 양궁대회 우승자이고 이번 대회에도 결승전까지 올라왔습니다. 결승전 상대는 어피치
입니다.
카카오배 양궁대회 운영위원회는 한 선수의 연속 우승보다는 다양한 선수들이 양궁대회에서 우승하기를 원합니다. 따라서, 양궁대회 운영위원회는 결승전 규칙을 전 대회 우승자인 라이언에게 불리하게 다음과 같이 정했습니다.
n
발을 다 쏜 후에 라이언이 화살 n
발을 쏩니다.현재 상황은 어피치가 화살 n
발을 다 쏜 후이고 라이언이 화살을 쏠 차례입니다.
라이언은 어피치를 가장 큰 점수 차이로 이기기 위해서 n
발의 화살을 어떤 과녁 점수에 맞혀야 하는지를 구하려고 합니다.
화살의 개수를 담은 자연수 n
, 어피치가 맞힌 과녁 점수의 개수를 10점부터 0점까지 순서대로 담은 정수 배열 info
가 매개변수로 주어집니다. 이때, 라이언이 가장 큰 점수 차이로 우승하기 위해 n
발의 화살을 어떤 과녁 점수에 맞혀야 하는지를 10점부터 0점까지 순서대로 정수 배열에 담아 return 하도록 solution 함수를 완성해 주세요. 만약, 라이언이 우승할 수 없는 경우(무조건 지거나 비기는 경우)는 [-1]
을 return 해주세요.
n
≤ 10info
의 길이 = 11info
의 원소 ≤ n
info
의 원소 총합 = n
info
의 i번째 원소는 과녁의 10 - i
점을 맞힌 화살 개수입니다. ( i는 0~10 사이의 정수입니다.)n
n
(꼭 n발을 다 쏴야 합니다.)10 - i
점을 맞힌 화살 개수입니다. ( i는 0~10 사이의 정수입니다.)[2,3,1,0,0,0,0,1,3,0,0]
과 [2,1,0,2,0,0,0,2,3,0,0]
를 비교하면 [2,1,0,2,0,0,0,2,3,0,0]
를 return 해야 합니다.[0,0,2,3,4,1,0,0,0,0,0]
과 [9,0,0,0,0,0,0,0,1,0,0]
를 비교하면[9,0,0,0,0,0,0,0,1,0,0]
를 return 해야 합니다.[-1]
을 return 해야 합니다.n
개의 화살을 11개의 과녁에 어떻게 분배할 것인지에 대한 완전탐색 문제였다.
처음 문제를 읽고 난 뒤 나는 그리드 탐색 문제인줄 알았다.
가장 큰 점수차를 내기 위해서는 가장 큰 10점을 우선적으로 챙겨야 한다고 생각했기 때문이다. 화살의 개수를 비용으로 생각하고 한번에 사용할 수 있는 비용을 점점 줄여가며 10점부터 살 수 있는지 검사하는 방법으로 문제를 풀어보았다.
이렇게 작성하니 테스트 케이스는 통과할 수 있었지만 제출하니 절반뿐만 통과되었다.
배열의 길이가 11이고, n
의 크기가 최대 10으로 모든 경우를 다 확인해 보아도, 이 될 것이다. (11개의 점수를 10개의 화살로 중복해서 선택)
여기서 좀 더 경우의 수를 줄이면 라이언이 해당 점수를 획득할지, 아닐지 두 가지로 나눌 수 있기 때문에 로 더 줄일 수 있다.
하지만 중복 순열로 계산할 경우, 입출력 예 4번에서 문제가 생긴다.
경우의 수를 계산한 뒤 화살이 남는 경우에는 0점 과녁에 남은 화살을 전부 소비하는 코드를 따로 작성해주어야 한다.
#include <string>
#include <vector>
using namespace std;
int sum(const vector<int> &list){
int s = 0;
for (auto i: list)
s += i;
return s;
}
vector<int> solution(int n, vector<int> info) {
vector<int> answer(info.size(), 0);
int maxGap = 0;
int count = 0;
while (count < (1 << info.size())){
vector<int> lion(info.size(), 0);
int cost = n;
int gap = 0;
for (int i=0; i < info.size(); i++){
if (count & 1<<i){
gap += 10 - i;
lion[i] = info[i] + 1;
}
else if (info[i] != 0){
gap -= 10 - i;
// lion[i] = 0;
}
}
if (sum(lion) <= n && gap >= maxGap){
if (sum(lion) < n){
lion[10] = n - sum(lion);
}
if (gap == maxGap){
for (int i =11; i >= 0; i--){
if (answer[i] > lion[i]){
break;
}
else if(answer[i] < lion[i]){
answer = lion;
break;
}
}
}
else{
maxGap = gap;
answer = lion;
}
}
count++;
}
if (maxGap == 0)
return {-1};
return answer;
}
입력 데이터가 굉장히 작고, 제한시간도 10초로 충분했다.
완전탐색으로 문제를 해결할 수 있다는것도 항상 기억해야겠다.