일단 스포당하기 싫은 사람은 뒤로 가기 눌러주셈.

https://www.acmicpc.net/problem/1493

Baekjoon Online JudgeBaekjoon Online Judgewww.acmicpc.net


일단 내 글의 목적은 위 문제의 정당한 풀이를 알고 싶음. 근데 그 풀이를 찾는 과정에서 어이가 없어서 길게 적어본다.

일단 그냥 구글에 "박스 채우기 백준" 이렇게만 검색해도 수많은 블로그 풀이글이 나옴. (열심히 사는 애들 저격하기 싫어서, 그냥 구글 검색해서 보셈)

보통 2가지 풀이로 귀결됨.

가장 큰 블록부터 쓰는 그리디에
1. 분할정복을 섞거나
2. 수학을 섞는
풀이임.

대다수가 자기가 생각한것처럼
큰 것부터 쓰면 좋겠죠? 한번 써보고 분할정복 해봅시다! 루틴임.

일단 첫번째 풀이에서 빠져 있는 가정은, 전체 문제에서 쓸 수 있는 가장 큰 블록을 쓰고, 나눠지는 (3부분 또는 7부분의) 직육면체 부분문제의 해를 합쳐도, 전체 문제해의 1. 존재성, 2. 최소성이 보장된다는 것임. 간단하게만 생각해봐도 3부분의 직육면체를 교차하는 블록을 놓는 해가 있을 수도 있는데 그런건 쌍그리 무시함. 5개 정도 글 읽어봤는데 그거 언급한게 하나도 없음.

두번째 풀이는 차라리 더 양반임. 일단 개요는, 그냥 어떻게 끼울지는 생각 안쓰고 수학적으로 쓸 수 있는만큼 쓰겠다. 이 풀이고, 놀랍게도 통과함.
조금 찾아보니까 질문게시판에 있는 갓-cubelover의 코드를 Python으로 옮긴거였음.

이거 풀이는, 그냥 구글에 "박스 채우기 파이썬" 검색하면 나오는거 보면 됨.

ㅋㅋㅋ 근데 어이없는게 1. 존나 분석한 것처럼 적어놨는데, 정작 잘못 베낌. 2. 그걸 다른 사람들이 베껴가서 똑같이 분석한척하고 틀린 코드를 제출함. 3. 정작 데이터가 약한지 그 틀린 풀이들이 모두 AC 받음 ㅋㅋㅋ

다음 두 코드를 한 번 비교해보셈.


for (i = 19; i >= 0; i--) 

w <<= 3;


for w, cnt in cube:

    before <<= 3

일단 C++ 코드는 20~0의 모든 A_i를 훑어봄. 그러니까 i가 연속적이여서 그 크기가 8배 곱해지는게 가능함.

문제는 파이썬 코드는 그냥 입력 그대로 받은거여서, w가 연속적이지 않을 수도 있는데 마음대로 가정하고, 그걸 또 이해한것마냥 적어놓음. 8배를 곱하는게 아니라 w의 차이에 3을 곱한걸 비트시프트 해야지 ㅇㅇ

아무튼 2가지 풀이가 모두  Proof-by-ac를 적었던가, 베껴서 양산된걸로 추측함.

그래서 본론: 이거 정당한 풀이 뭐임?