만족은 하되 안주하지는 말자

기록해야 기억한다

프로그래밍/programmers&bj

[C++][알고리즘] 프로그래머스::체육복 풀이

D36choi 2019. 8. 20. 16:30
728x90

https://programmers.co.kr/learn/courses/30/lessons/42862

 

코딩테스트 연습 - 체육복 | 프로그래머스

점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다. 체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다. 전체

programmers.co.kr

설명

탐욕법

탐욕법 카테고리 문제이므로, 최적의 해를 구한다는 보장은 없고, 모든 문제에 대해 그리디알고리즘을 적용할 수 없다.

어떤 문제에 대해서는 동적프로그래밍보다 더 높은 효율을 보이지만 매번 이 알고리즘이 더 최선의 해를 선택한다는 보장이 없다 이거다.

 

시행착오

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
 
int check(int lostmem, vector<int>&reserve) {
    vector<int>::iterator iter;
    for (int i = 0; i < reserve.size(); i++) {
        if (lostmem - 1 == reserve[i]) {
            reserve.erase(reserve.begin() + i);
            return 1;
        }
        if (lostmem + 1 == reserve[i]) {
            reserve.erase(reserve.begin() + i);
            return 1;
        }
    }
    return 0;
}
int solution(int n, vector<int> lost, vector<int> reserve) {
    int answer = n - lost.size();
    for (int i = 0; i < lost.size(); i++) {
        answer += check(lost[i], reserve);
    }
 
    return answer;
}
cs

맨처음엔 이터레이터와 vector 클래스가 가지고있는 erase 함수를 이용해서 reserve 배열 즉,

유니폼이 2개인 애들이 자신의 여분을 빌려주면 reserve 배열에서 삭제하고 

check 함수의 return value를 answer에 더해주면서 유니폼을 입을수 있는 사람 수를 구하는 방식인데...

 

몇몇의 테스트케이스에서 실패가 되었다. 다른 방식으로 맞추고 나도 어느 부분이 문제인진 잘 모르겠다.

 

 

다른 풀이법(만점)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 
int solution(int n, vector<int> lost, vector<int> reserve) {
    vector<int> list(n, 1);
    int answer=0;
    for (int i = 0; i < lost.size(); i++) {
        list[lost[i] - 1]--;
    }
    for (int i = 0; i < reserve.size(); i++) {
        list[reserve[i] - 1]++;
    }
    for (int i = 0; i < list.size(); i++) {
        if (list[i] == 0) {
            if (i != 0 && list[i - 1== 2) {
                list[i - 1]--;
                list[i]++;
            }
            else if (i != list.size() - 1 && list[i + 1== 2) {
                list[i + 1]--;
                list[i]++;
            }
        }
    }
    for (int i = 0; i < list.size(); i++) {
        if (list[i] !=0) {
            answer++;
        }
    }
    return answer;
}
cs

전에 풀던 방식은

n=6에 lost는 {1,3,5} 면, 체육복이 없는 3번째 학생의 왼쪽 오른쪽(2,4) 학생이 여분이 있는지 보고

(reserve 배열에 2,4가 있는지 check) 있으면 reserve 배열의 2를 erase 하고 1을 return 해주는 방식.

 

이번엔 애초에 list 라는 이름의 vector를 선언하고, 체육복이 없으면 0, 있으면(여분이 있는 학생포함) 1의 상태를 갖게한다. 이런 차이가 있는 것!


틀렸던 방식 : index number = 활용안함 , index에 저장된 값 = x번째 학생

수정 후의 방식 : index number = x번쨰 학생, index에 저장된 값 = 체육복을 가지고 있는지 아닌지의 상태


 

이건 만점이 아니지 솔직히

결국 요번에도 OTK(원턴킬) 실패. 언제쯤 한번에 성공하는 쾌감을 맛볼 수 있을까 ㅠ.