인프런 커뮤니티 질문&답변

심재욱님의 프로필 이미지
심재욱

작성한 질문수

10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트

4 - A 재질문합니다

작성

·

300

0

http://boj.kr/cd6fbe132cfd4b3dbe5e0c746db37b16

실수로 공유를 안눌렀네요 ㅎㅎ..

질문했던 글 복붙해서 다시 올리겠습니다!

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

제가 찾아본 모든 반례 체크 다 통과했습니다.

아무래도 사전순 판단하는 로직때문에 틀린 것 같긴한데,,

ans 배열과 sel 배열을 비교해서 ans의 요소가 더 크면 break를 해주고 sel의 값으로 바꿔 주었는데 반례가 딱히 떠오르지 않으니까 답답합니다..

답변 1

0

큰돌님의 프로필 이미지
큰돌
지식공유자

안녕하세요 재욱님 ㅎㅎ

정말 잘 짜셨네요. ㅎㅎ

제가 주석 달아놨는데 참고 부탁드립니다.

#include <bits/stdc++.h>
using namespace std;


struct nut
{
    int a, b, c, d, e;
    
    nut(int a, int b, int c, int d, int e) : a(a), b(b), c(c), d(d), e(e) { }
    nut() { }
};

int n , m = 2100000000;

nut nu;
vector<nut> v;
vector<int> sel, ans;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
    
    int a, b, c, d, e;
    cin >> n;
    
    cin >> nu.a >> nu.b >> nu.c >> nu.d;
    for (int i = 0; i < n; i++)
    {
        cin >> a >> b >> c >> d >> e;
        v.push_back(nut(a, b, c, d, e));
    }
    
    for (int i = 1; i < (1 << n); i++)
    {
        //굿.
        nut nutri(0, 0, 0, 0, 0);
        sel.clear();
        for (int j = 0; j < n; j++)
        {
            if (i & (1 << j))sel.push_back(j);
        }
        
        for (int idx : sel){
            nutri.a += v[idx].a;
            nutri.b += v[idx].b;
            nutri.c += v[idx].c;
            nutri.d += v[idx].d;
            nutri.e += v[idx].e;
        } 

        if (nutri.a >= nu.a && nutri.b >= nu.b && nutri.c >= nu.c && nutri.d >= nu.d)
        {  
            if (m > nutri.e){    
                m = nutri.e;
                ans.clear();
                // 제가 j를 idx로 바꾼 이유는요. 이코드는 j여도 문제가 없어요.
                // 그치만 변수명 같은 경우 이렇게 j를 순회하면서 sel에다가 push하는 로직을 하고 여기서는 
                // sel의 요소를 넣을 때 j를 또 쓰잖아요. 이렇게 됬을 때 나중에 헷갈릴 수가 있어서 맞왜틀에 빠질 수 있거든요. 
                // 넉넉히 변수명 하나 더 씁시다.
                for (int idx : sel) ans.push_back(idx + 1);
            } // 굿. 
            else if (m == nutri.e){
                bool flag = false; 
                // 이부분!
                // ans 1 2 3 4
                // sel 1 2 3 인 경우가 반례입니다. 
                int size = min(ans.size(), sel.size());
                
                for (int j = 0; j < size; j++)
                {
                    if (ans[j] > sel[j] + 1){
                        flag = true;
                        break;
                    }
                }
                
                if (flag) {
                    ans.clear();
                    for (int idx : sel) ans.push_back(idx + 1);
                }
            }
        }
    
    }
    
    if (m == 2100000000) m = -1;
    //endl은 쓰지 말아주세요 - 교안 참고
    cout << m << endl; 
    cout << ba[0];
    if(m != -1){
        for (int i = 0; i < ans.size(); i++) cout << ans[i] << " ";
        cout << '\n'; 
    } 
}
 또 질문 있으시면 언제든지 질문 부탁드립니다.

좋은 수강평과 별점 5점은 제게 큰 힘이 됩니다. :)

감사합니다.

강사 큰돌 올림.

심재욱님의 프로필 이미지
심재욱
질문자

강사님 좋은 답변 너무 감사드립니다!!

제가 생각한게 비트마스킹으로 모든 경우의 수를 탐색 할 때는 1 2 3 4가 1 2 3보다 뒤에 탐색 되기 때문에 애초에 ans가 1 2 3 4일 때 sel이 1 2 3 이 될 경우가 없어서 괜찮다고 생각하는데 이게 아닌건가요?..

큰돌님의 프로필 이미지
큰돌
지식공유자

재욱님 안녕하세요 ㅎㅎ 그 말씀이 맞습니다. 1, 2, 3 .... 1, 2, 3, 4이렇게 되서

사실 그 반례가 적용될 코드는 아니긴 하네요.. 흠....

이부분은 제가 시간날 때 다시한번 생각해볼게요.

심재욱님의 프로필 이미지
심재욱

작성한 질문수

질문하기