백준 1493번 (박스 채우기, C++, 분할 정복) [BAEKJOON]

박스 채우기

www.acmicpc.net/problem/1493

시간 제한메모리 제한제출정답맞힌 사람정답 비율
2 초128 MB4718127190927.224%

문제

세준이는 length × width × height 크기의 박스를 가지고 있다.

그리고 세준이는 이 박스를 큐브를 이용해서 채우려고 한다.

큐브는 정육면체 모양이며, 한 변의 길이는 2의 제곱꼴이다.

(1×1×1, 2×2×2, 4×4×4, 8×8×8, …)

세준이가 가지고 있는 박스의 종류와 큐브의 종류와 개수가 주어졌을 때,

박스를 채우는데 필요한 큐브의 최소 개수를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 세 자연수 length width height가 주어진다.

둘째 줄에 세준이가 가지고 있는 큐브의 종류의 개수 N이 주어진다.

셋째 줄부터 총 N개의 줄에 큐브의 종류 Ai와 개수 Bi가 i가 증가하는 순서대로 주어진다.

큐브의 종류는 한 변의 길이를 나타낼 때 쓰는 2i에서 i이다.

출력

첫째 줄에 필요한 큐브의 개수의 최솟값을 출력한다.

만약 채울 수 없다면 -1을 출력한다.

제한

  • 1 ≤ length, width, height ≤ 106
  • 1 ≤ n ≤ 20
  • 0 ≤ Ai < 20
  • 0 ≤ Bi ≤ 106
  • Ai ≠ Aj (i ≠ j)

예제 입력 1

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
4 4 8
3
0 10
1 10
2 1
4 4 8 3 0 10 1 10 2 1
4 4 8
3
0 10
1 10
2 1

예제 출력 1

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
9
9
9

예제 입력 2

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
4 4 8
3
0 10
1 10
2 10
4 4 8 3 0 10 1 10 2 10
4 4 8
3
0 10
1 10
2 10

예제 출력 2

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
2
2
2

예제 입력 3

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
10 10 11
1
0 2000
10 10 11 1 0 2000
10 10 11
1
0 2000

예제 출력 3

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
1100
1100
1100

예제 입력 4

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
10 10 11
1
0 1099
10 10 11 1 0 1099
10 10 11
1
0 1099

예제 출력 4

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
-1
-1
-1

예제 입력 5

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
37 42 59
6
0 143821
1 14382
2 1438
3 143
4 14
5 1
37 42 59 6 0 143821 1 14382 2 1438 3 143 4 14 5 1
37 42 59
6
0 143821
1 14382
2 1438
3 143
4 14
5 1

예제 출력 5

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
5061
5061
5061

출처

  • 문제를 번역한 사람: baekjoon
  • 문제의 오타를 찾은 사람: ho94949

알고리즘 분류


length × width × height 크기의 박스

이 박스를 큐브로 채우려고 한다.

큐브의 크기는 정육면체 모양이며 한 변의 길이는 2의 제곱 꼴 1, 2, 4, 8…

박스를 채우는데 필요한 큐브의 최소 개수를 찾는 문제

4 4 8 // 박스 length × width × height

3 // 큐브의 개수

0 10 // 변의 길이 : 2^0 10개 넓이 1 10개

1 10 // 변의 길이 : 2^1 10개 넓이 8 10개

2 1 // 변의 길이 : 2^2 1개 넓이 64 1개

넓이 128 64 + 10 + 10 + 10 + 10 + 10 + 10

박스는 부피

큐브는 각 큐브의 한 변의 길이와 개수만 가지고 있으면 될 것 같다

박스가 큐브의 개수와는 상관없이

만들어질 수 있는 경우의 수를 조건과 비교하면서 하면 어떨까???

입력 확인

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include <iostream>
#include <set>
using namespace std;
// 큐브의 변의 길이 순으로 내림차순 정렬
set<int, greater<int>> cubeSet;
set<int, greater<int>> ::iterator iter;
// 큐브의 개수를 저장 / 인덱스는 2^index
int cubeNumber[21] = { 0 };
// 박스의 가 세 높
int length, width, height = 0;
// 박스의 부피
int boxArea = 0;
// 큐브의 종류 , 큐브의 수
int type, Number = 0;
void Initializaion()
{
cin >> length >> width >> height;
boxArea = length * width * height;
int N = 0;
cin >> N;
while (N > 0)
{
cin >> type >> Number;
cubeSet.insert(type);
cubeNumber[type] += Number;
N--;
}
}
int main()
{
Initializaion();
cout << "박스의 부피 : " << boxArea << "\n";
for (iter = cubeSet.begin(); iter != cubeSet.end(); iter++)
{
cout << "큐브 변의 길이 2^ " << *iter << " 박스의 개수 : " << cubeNumber[*iter] << " \n";
}
return 0;
}
#include <iostream> #include <set> using namespace std; // 큐브의 변의 길이 순으로 내림차순 정렬 set<int, greater<int>> cubeSet; set<int, greater<int>> ::iterator iter; // 큐브의 개수를 저장 / 인덱스는 2^index int cubeNumber[21] = { 0 }; // 박스의 가 세 높 int length, width, height = 0; // 박스의 부피 int boxArea = 0; // 큐브의 종류 , 큐브의 수 int type, Number = 0; void Initializaion() { cin >> length >> width >> height; boxArea = length * width * height; int N = 0; cin >> N; while (N > 0) { cin >> type >> Number; cubeSet.insert(type); cubeNumber[type] += Number; N--; } } int main() { Initializaion(); cout << "박스의 부피 : " << boxArea << "\n"; for (iter = cubeSet.begin(); iter != cubeSet.end(); iter++) { cout << "큐브 변의 길이 2^ " << *iter << " 박스의 개수 : " << cubeNumber[*iter] << " \n"; } return 0; }
#include <iostream>
#include <set>

using namespace std;

// 큐브의 변의 길이 순으로 내림차순 정렬
set<int, greater<int>> cubeSet;
set<int, greater<int>> ::iterator iter;

// 큐브의 개수를 저장 / 인덱스는 2^index
int cubeNumber[21] = { 0 };

// 박스의 가 세 높
int length, width, height = 0;

// 박스의 부피
int boxArea = 0;

// 큐브의 종류 , 큐브의 수
int type, Number = 0;

void Initializaion()
{
	cin >> length >> width >> height;
	boxArea = length * width * height;
	int N = 0;
	cin >> N;
	while (N > 0)
	{
		cin >> type >> Number;
		cubeSet.insert(type);
		cubeNumber[type] += Number;
		N--;
	}
}

int main()
{
	Initializaion();
	cout << "박스의 부피 : " << boxArea << "\n";
	for (iter = cubeSet.begin(); iter != cubeSet.end(); iter++)
	{
		cout << "큐브 변의 길이 2^ " << *iter << "   박스의 개수 :  " << cubeNumber[*iter] << " \n";
	}
    
	return 0;
}

마지막 테스트 케이스에서 망… 함 ㅠ

부피로 접근하는 방법은 잘못된 방법이다

큐브들의 부피가 박스의 부피와 같다고 큐브가 박스 모양일 거라는 착각…

잘못된 로직과 코드 1

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include <iostream>
#include <set>
#include <cmath>
using namespace std;
// 큐브의 변의 길이 순으로 내림차순 정렬
set<int, greater<int>> cubeSet;
set<int, greater<int>> ::iterator iter;
// 큐브의 개수를 저장 / 인덱스는 2^index
int cubeNumber[21] = { 0 };
// 박스의 가 세 높
int length, width, height = 0;
// 박스의 넓이
int boxArea = 0;
// 큐브의 종류 , 큐브의 수
int type, Number = 0;
void Initializaion()
{
cin >> length >> width >> height;
boxArea = length * width * height;
int N = 0;
cin >> N;
while (N > 0)
{
cin >> type >> Number;
cubeSet.insert(type);
cubeNumber[type] += Number;
N--;
}
}
void CubeCheck(int cnt, int value)
{
if (value == boxArea)
{
cout << "찾았다 : " << cnt << " boxArea : " << boxArea << " value : " << value << "\n";
for (auto it = cubeSet.begin(); it != cubeSet.end(); it++)
{
cout << "it : " << *it << " cubeNumber[*it] : " << cubeNumber[*it] << "\n";
}
exit(0);
}
for (auto it = cubeSet.begin(); it != cubeSet.end(); it++)
{
if (cubeNumber[*it] == 0 || value > boxArea )
{
return;
}
//cout << "cubeNumber[" << *it << "] : " << cubeNumber[*it] << "\n";
cubeNumber[*it]--;
//cout << "cnt : " << cnt << " 들어갈 때 : " << value << " ";
CubeCheck(cnt + 1, value + pow(pow(2,*it),3));
cubeNumber[*it]++;
}
cout << -1;
exit(0);
}
int main()
{
Initializaion();
CubeCheck(0, 0);
return 0;
}
#include <iostream> #include <set> #include <cmath> using namespace std; // 큐브의 변의 길이 순으로 내림차순 정렬 set<int, greater<int>> cubeSet; set<int, greater<int>> ::iterator iter; // 큐브의 개수를 저장 / 인덱스는 2^index int cubeNumber[21] = { 0 }; // 박스의 가 세 높 int length, width, height = 0; // 박스의 넓이 int boxArea = 0; // 큐브의 종류 , 큐브의 수 int type, Number = 0; void Initializaion() { cin >> length >> width >> height; boxArea = length * width * height; int N = 0; cin >> N; while (N > 0) { cin >> type >> Number; cubeSet.insert(type); cubeNumber[type] += Number; N--; } } void CubeCheck(int cnt, int value) { if (value == boxArea) { cout << "찾았다 : " << cnt << " boxArea : " << boxArea << " value : " << value << "\n"; for (auto it = cubeSet.begin(); it != cubeSet.end(); it++) { cout << "it : " << *it << " cubeNumber[*it] : " << cubeNumber[*it] << "\n"; } exit(0); } for (auto it = cubeSet.begin(); it != cubeSet.end(); it++) { if (cubeNumber[*it] == 0 || value > boxArea ) { return; } //cout << "cubeNumber[" << *it << "] : " << cubeNumber[*it] << "\n"; cubeNumber[*it]--; //cout << "cnt : " << cnt << " 들어갈 때 : " << value << " "; CubeCheck(cnt + 1, value + pow(pow(2,*it),3)); cubeNumber[*it]++; } cout << -1; exit(0); } int main() { Initializaion(); CubeCheck(0, 0); return 0; }
#include <iostream>
#include <set>
#include <cmath>

using namespace std;

// 큐브의 변의 길이 순으로 내림차순 정렬
set<int, greater<int>> cubeSet;
set<int, greater<int>> ::iterator iter;

// 큐브의 개수를 저장 / 인덱스는 2^index
int cubeNumber[21] = { 0 };

// 박스의 가 세 높
int length, width, height = 0;

// 박스의 넓이
int boxArea = 0;

// 큐브의 종류 , 큐브의 수
int type, Number = 0;


void Initializaion()
{
	cin >> length >> width >> height;
	boxArea = length * width * height;
	int N = 0;
	cin >> N;
	while (N > 0)
	{
		cin >> type >> Number;
		cubeSet.insert(type);
		cubeNumber[type] += Number;
		N--;
	}
}

void CubeCheck(int cnt, int value)
{

	if (value == boxArea)
	{
		cout << "찾았다 : " << cnt << "  boxArea : " << boxArea <<  "  value : " << value << "\n";
		for (auto it = cubeSet.begin(); it != cubeSet.end(); it++)
		{
			cout << "it : " << *it << "  cubeNumber[*it] : " << cubeNumber[*it] << "\n";
		}
		exit(0);
	}

	for (auto it = cubeSet.begin(); it != cubeSet.end(); it++)
	{
		if (cubeNumber[*it] == 0 || value > boxArea )
		{
			return;
		}
		//cout << "cubeNumber[" << *it << "]  : " << cubeNumber[*it] << "\n";
		cubeNumber[*it]--;
		//cout << "cnt : " << cnt << " 들어갈 때 : " << value << " ";
		CubeCheck(cnt + 1, value + pow(pow(2,*it),3));
		cubeNumber[*it]++;
	}
	cout << -1;
	exit(0);
}

int main()
{
	Initializaion();
	CubeCheck(0, 0);
	return 0;
}

그렇다면 박스에서 접근해야 한다.

박스를 큐브의 규격을 기준으로 분할하여 그리디 알고리즘을 적용하면서 푸는 것 인가?

잘못된 로직과 코드 2

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include <iostream>
#include <set>
#include <cmath>
#include <algorithm>
using namespace std;
// 큐브의 변의 길이 순으로 내림차순 정렬
set<int, greater<int>> cubeSet;
set<int, greater<int>> ::iterator iter;
// 큐브의 개수를 저장 / 인덱스는 2^index
int cubeNumber[21] = { 0 };
int cubeNeedNumber[21] = { 0 };
// 박스의 X,Y,Z
int BoxXYZ[3] = { 0 };
int temp[3] = { 0 };
// 큐브의 종류 , 큐브의 수
int type, Number = 0;
int cubeCNT = 0;
void Initializaion()
{
cin >> BoxXYZ[0] >> BoxXYZ[1] >> BoxXYZ[2];
sort(BoxXYZ, BoxXYZ + (sizeof(BoxXYZ)/sizeof(BoxXYZ[0])));
int N = 0;
cin >> N;
while (N > 0)
{
cin >> type >> Number;
cubeSet.insert(type);
cubeNumber[type] += Number;
N--;
}
}
// 가장 큰 X를 기준으로 Z를 채워나감
// 들어오는 값은 X의 길이/Z의 남은 길이/ 몇번 나누었는지 확인(0부터 시작)
// 이 함수의 목적은 Z가 0이 될때까지 큐브를 찾는 것
void CubeCheckZ(int N, int leftZ, int divisionCount, int st)
{
for (;leftZ >= pow(2, N);)
{
cout << "leftZ : " << leftZ << " pow(2, N) : " << pow(2, N) << "\n";
if (divisionCount == 0 && st == pow(2, N))
{
BoxXYZ[2] -= st;
st = -1;
}
if (st == -1)
{
cubeNeedNumber[N] += pow(4, divisionCount);
}
else
{
cubeNeedNumber[N] += pow(4, divisionCount) * (st / pow(2, N));
}
leftZ -= pow(2, N);
if (leftZ == 0)
{
return;
}
}
// 남은 Z의 길이보다 pow(2, N)가 더 큰 상황
for (;leftZ < pow(2, N);)
{
N--;
divisionCount++;
cout << "남은 Z의 길이보다 작은 박스 값 찾기 : " << " N : " << N << " pow(2, N) : " << pow(2, N) << " leftZ : " << leftZ << "\n";
}
CubeCheckZ(N, leftZ, divisionCount, st);
}
// 박스 전체의 X길이와 Z의 길이
void CubeCheckX(int BoxX, int BoxZ, int st, int boxY)
{
if (BoxX == 0)
{
return;
}
// 처음 할 때
int N = 0;
for (int i = 0; i <= 20; i++)
{
if (boxY < pow(2, i))
{
N = i - 1;
break;
}
else if (boxY == pow(2, i))
{
N = i;
break;
}
//X의 값에 가장 근접한 2^i 를 구함
if (BoxX < pow(2, i) )
{
N = i - 1;
cout << "높을때 : " << N ;
//cubeNeedNumber[N]++;
break;
}
else if (BoxX == pow(2, i) )
{
//cout << "BoxX : " << BoxX << " 같을때" << N;
N = i;
//cubeNeedNumber[N]++;
break;
}
}
if (st <= pow(2,N))
{
st = pow(2, N);
}
// 박스의 Z길이보다 작거나 같은 2^N 의 N / 박스의 Z 길이
BoxX -= pow(2, N);
CubeCheckZ(N , BoxZ, 0, st);
cout << "BoxX : " << BoxX << "\n";
CubeCheckX(BoxX, BoxZ, st, boxY);
}
int main()
{
Initializaion();
for (;BoxXYZ[2] > 0;)
{
CubeCheckX(BoxXYZ[0], BoxXYZ[1], 0, BoxXYZ[2]);
cout << "BoxXYZ[2] : " << BoxXYZ[2] << "\n";
}
for (iter = cubeSet.begin(); iter != cubeSet.end(); iter++)
{
cout << "cubeNeedNumber[" << *iter << "] : " << cubeNeedNumber[*iter] << "\n";
}
return 0;
}
#include <iostream> #include <set> #include <cmath> #include <algorithm> using namespace std; // 큐브의 변의 길이 순으로 내림차순 정렬 set<int, greater<int>> cubeSet; set<int, greater<int>> ::iterator iter; // 큐브의 개수를 저장 / 인덱스는 2^index int cubeNumber[21] = { 0 }; int cubeNeedNumber[21] = { 0 }; // 박스의 X,Y,Z int BoxXYZ[3] = { 0 }; int temp[3] = { 0 }; // 큐브의 종류 , 큐브의 수 int type, Number = 0; int cubeCNT = 0; void Initializaion() { cin >> BoxXYZ[0] >> BoxXYZ[1] >> BoxXYZ[2]; sort(BoxXYZ, BoxXYZ + (sizeof(BoxXYZ)/sizeof(BoxXYZ[0]))); int N = 0; cin >> N; while (N > 0) { cin >> type >> Number; cubeSet.insert(type); cubeNumber[type] += Number; N--; } } // 가장 큰 X를 기준으로 Z를 채워나감 // 들어오는 값은 X의 길이/Z의 남은 길이/ 몇번 나누었는지 확인(0부터 시작) // 이 함수의 목적은 Z가 0이 될때까지 큐브를 찾는 것 void CubeCheckZ(int N, int leftZ, int divisionCount, int st) { for (;leftZ >= pow(2, N);) { cout << "leftZ : " << leftZ << " pow(2, N) : " << pow(2, N) << "\n"; if (divisionCount == 0 && st == pow(2, N)) { BoxXYZ[2] -= st; st = -1; } if (st == -1) { cubeNeedNumber[N] += pow(4, divisionCount); } else { cubeNeedNumber[N] += pow(4, divisionCount) * (st / pow(2, N)); } leftZ -= pow(2, N); if (leftZ == 0) { return; } } // 남은 Z의 길이보다 pow(2, N)가 더 큰 상황 for (;leftZ < pow(2, N);) { N--; divisionCount++; cout << "남은 Z의 길이보다 작은 박스 값 찾기 : " << " N : " << N << " pow(2, N) : " << pow(2, N) << " leftZ : " << leftZ << "\n"; } CubeCheckZ(N, leftZ, divisionCount, st); } // 박스 전체의 X길이와 Z의 길이 void CubeCheckX(int BoxX, int BoxZ, int st, int boxY) { if (BoxX == 0) { return; } // 처음 할 때 int N = 0; for (int i = 0; i <= 20; i++) { if (boxY < pow(2, i)) { N = i - 1; break; } else if (boxY == pow(2, i)) { N = i; break; } //X의 값에 가장 근접한 2^i 를 구함 if (BoxX < pow(2, i) ) { N = i - 1; cout << "높을때 : " << N ; //cubeNeedNumber[N]++; break; } else if (BoxX == pow(2, i) ) { //cout << "BoxX : " << BoxX << " 같을때" << N; N = i; //cubeNeedNumber[N]++; break; } } if (st <= pow(2,N)) { st = pow(2, N); } // 박스의 Z길이보다 작거나 같은 2^N 의 N / 박스의 Z 길이 BoxX -= pow(2, N); CubeCheckZ(N , BoxZ, 0, st); cout << "BoxX : " << BoxX << "\n"; CubeCheckX(BoxX, BoxZ, st, boxY); } int main() { Initializaion(); for (;BoxXYZ[2] > 0;) { CubeCheckX(BoxXYZ[0], BoxXYZ[1], 0, BoxXYZ[2]); cout << "BoxXYZ[2] : " << BoxXYZ[2] << "\n"; } for (iter = cubeSet.begin(); iter != cubeSet.end(); iter++) { cout << "cubeNeedNumber[" << *iter << "] : " << cubeNeedNumber[*iter] << "\n"; } return 0; }
#include <iostream>
#include <set>
#include <cmath>
#include <algorithm>

using namespace std;

// 큐브의 변의 길이 순으로 내림차순 정렬
set<int, greater<int>> cubeSet;
set<int, greater<int>> ::iterator iter;

// 큐브의 개수를 저장 / 인덱스는 2^index
int cubeNumber[21] = { 0 };
int cubeNeedNumber[21] = { 0 };

// 박스의 X,Y,Z
int BoxXYZ[3] = { 0 };
int temp[3] = { 0 };

// 큐브의 종류 , 큐브의 수
int type, Number = 0;

int cubeCNT = 0;

void Initializaion()
{

	cin >> BoxXYZ[0] >> BoxXYZ[1] >> BoxXYZ[2];
	sort(BoxXYZ, BoxXYZ + (sizeof(BoxXYZ)/sizeof(BoxXYZ[0])));
	int N = 0;
	cin >> N;
	while (N > 0)
	{
		cin >> type >> Number;
		cubeSet.insert(type);
		cubeNumber[type] += Number;
		N--;
	}
}

// 가장 큰 X를 기준으로 Z를 채워나감
// 들어오는 값은 X의 길이/Z의 남은 길이/ 몇번 나누었는지 확인(0부터 시작)
// 이 함수의 목적은 Z가 0이 될때까지 큐브를 찾는 것
void CubeCheckZ(int N, int leftZ, int divisionCount, int st)
{

	for (;leftZ >= pow(2, N);)
	{
		cout << "leftZ : " << leftZ << " pow(2, N) : " << pow(2, N) << "\n";
		if (divisionCount == 0 && st == pow(2, N))
		{
			BoxXYZ[2] -= st;
			st = -1;
		}
		
		if (st == -1)
		{
			cubeNeedNumber[N] += pow(4, divisionCount);
		}
		else
		{
			cubeNeedNumber[N] += pow(4, divisionCount) * (st / pow(2, N));
		}

		leftZ -= pow(2, N);
		
		if (leftZ == 0)
		{
			return;
		}
	}

	// 남은 Z의 길이보다 pow(2, N)가 더 큰 상황 
	for (;leftZ < pow(2, N);)
	{
		N--;
		divisionCount++;
		cout << "남은 Z의 길이보다 작은 박스 값 찾기 : " << " N : " << N << "  pow(2, N) : " << pow(2, N) << "  leftZ  :  " << leftZ << "\n";
	}

	CubeCheckZ(N, leftZ, divisionCount, st);
}


// 박스 전체의 X길이와 Z의 길이
void CubeCheckX(int BoxX, int BoxZ, int st, int boxY)
{
	if (BoxX == 0)
	{
		return;
	}
	// 처음 할 때
	int N = 0;
	for (int i = 0; i <= 20; i++)
	{
		if (boxY < pow(2, i))
		{
			N = i - 1;
			break;
		}
		else if (boxY == pow(2, i))
		{
			N = i;
			break;
		}
		
		//X의 값에 가장 근접한 2^i 를 구함
		if (BoxX < pow(2, i) )
		{

			N = i - 1;
			cout << "높을때 : " << N ;
			//cubeNeedNumber[N]++;
			break;

		}
		else if (BoxX == pow(2, i) )
		{
			//cout << "BoxX : " << BoxX << " 같을때" << N;
			N = i;
			//cubeNeedNumber[N]++;
			break;
		}
	}
	
	if (st <= pow(2,N))
	{
		st = pow(2, N);
	}

	// 박스의 Z길이보다 작거나 같은 2^N 의 N / 박스의 Z 길이 
	BoxX -= pow(2, N);
	CubeCheckZ(N , BoxZ, 0, st);
	cout << "BoxX  :  " << BoxX << "\n";
	CubeCheckX(BoxX, BoxZ, st, boxY);
}





int main()
{
	Initializaion();

	for (;BoxXYZ[2] > 0;)
	{
		CubeCheckX(BoxXYZ[0], BoxXYZ[1], 0, BoxXYZ[2]);
		cout << "BoxXYZ[2] : " << BoxXYZ[2] << "\n";
	}


	for (iter = cubeSet.begin(); iter != cubeSet.end(); iter++)
	{
		cout << "cubeNeedNumber[" << *iter << "]  : " << cubeNeedNumber[*iter] << "\n";

	}
	return 0;
}

잘못된 로직과 코드 3

작성하다 보니 내가 왜 이렇게 작성했는지 이해할 수 없다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include <iostream>
#include <set>
#include <cmath>
#include <algorithm>
using namespace std;
set<int, greater<int>> cubeSet;
set<int, greater<int>> ::iterator iter;
int cubeNumber[21] = { 0 };
int cubeNeedNumber[21] = { 0 };
long long BoxXYZ[3] = { 0 };
int type, Number = 0;
void Initializaion()
{
cin >> BoxXYZ[0] >> BoxXYZ[1] >> BoxXYZ[2];
sort(BoxXYZ, BoxXYZ + (sizeof(BoxXYZ)/sizeof(BoxXYZ[0])));
int N = 0;
cin >> N;
while (N > 0)
{
cin >> type >> Number;
cubeSet.insert(type);
cubeNumber[type] += Number;
N--;
}
}
void CubeCheckZ(long long N, long long leftZ, long long divisionCount, long long MaxX, bool firstCheck)
{
for (;leftZ >= pow(2, N);)
{
if (MaxX == pow(2, N) || leftZ >= pow(2, N) && firstCheck)
{
if (N == 0)
{
cubeNeedNumber[N] += leftZ;
leftZ = 0;
continue;
}
cubeNeedNumber[N] += pow(4, divisionCount);
cout << "pow(4, divisionCount) : " << pow(4, divisionCount) << " divisionCount : " << divisionCount << " N : "<< N << "\n";
leftZ -= pow(2, N);
continue;
}
if (leftZ >= pow(2, N) && !firstCheck)
{
if (N == 0)
{
cubeNeedNumber[N] += leftZ * MaxX / pow(2, N);
leftZ = 0;
continue;
}
cubeNeedNumber[N] += MaxX / pow(2, N);
cout << "MaxX / pow(2, N) : " << MaxX / pow(2, N) << " " << MaxX << " / " << pow(2, N) << "\n";
leftZ -= pow(2, N);
}
}
if (leftZ == 0)
{
cout << "leftZ : " << leftZ << "\n";
return;
}
while(leftZ < pow(2, N))
{
N--;
divisionCount++;
}
CubeCheckZ(N, leftZ, divisionCount, MaxX, firstCheck);
}
void CubeCheckX(long long BoxX, long long BoxZ, long long MaxX, long long boxY, bool firstCheck)
{
if (BoxX == 0)
{
BoxXYZ[2] -= MaxX;
return;
}
int N = 0;
for (int i = 0; i <= 20; i++)
{
if (BoxX < pow(2, i) || (BoxXYZ[2] < pow(2, i)))
{
N = i - 1;
BoxX -= pow(2, N);
break;
}
else if (BoxX == pow(2, i) || (BoxXYZ[2] == pow(2, i)))
{
N = i;
BoxX -= pow(2, N);
break;
}
}
if (MaxX < pow(2,N))
{
MaxX = pow(2, N);
}
CubeCheckZ(N , BoxZ, 0, MaxX, firstCheck);
firstCheck = false;
CubeCheckX(BoxX , BoxZ, MaxX, boxY, firstCheck);
}
int main()
{
Initializaion();
while (BoxXYZ[2] != 0)
{
CubeCheckX(BoxXYZ[0], BoxXYZ[1], 0, BoxXYZ[2], true);
cout << BoxXYZ[2] << " \n";
}
for (iter = cubeSet.begin(); iter != cubeSet.end(); iter++)
{
cout << "cubeNeedNumber[" << *iter << "] : " << cubeNeedNumber[*iter] << "\n";
}
return 0;
}
#include <iostream> #include <set> #include <cmath> #include <algorithm> using namespace std; set<int, greater<int>> cubeSet; set<int, greater<int>> ::iterator iter; int cubeNumber[21] = { 0 }; int cubeNeedNumber[21] = { 0 }; long long BoxXYZ[3] = { 0 }; int type, Number = 0; void Initializaion() { cin >> BoxXYZ[0] >> BoxXYZ[1] >> BoxXYZ[2]; sort(BoxXYZ, BoxXYZ + (sizeof(BoxXYZ)/sizeof(BoxXYZ[0]))); int N = 0; cin >> N; while (N > 0) { cin >> type >> Number; cubeSet.insert(type); cubeNumber[type] += Number; N--; } } void CubeCheckZ(long long N, long long leftZ, long long divisionCount, long long MaxX, bool firstCheck) { for (;leftZ >= pow(2, N);) { if (MaxX == pow(2, N) || leftZ >= pow(2, N) && firstCheck) { if (N == 0) { cubeNeedNumber[N] += leftZ; leftZ = 0; continue; } cubeNeedNumber[N] += pow(4, divisionCount); cout << "pow(4, divisionCount) : " << pow(4, divisionCount) << " divisionCount : " << divisionCount << " N : "<< N << "\n"; leftZ -= pow(2, N); continue; } if (leftZ >= pow(2, N) && !firstCheck) { if (N == 0) { cubeNeedNumber[N] += leftZ * MaxX / pow(2, N); leftZ = 0; continue; } cubeNeedNumber[N] += MaxX / pow(2, N); cout << "MaxX / pow(2, N) : " << MaxX / pow(2, N) << " " << MaxX << " / " << pow(2, N) << "\n"; leftZ -= pow(2, N); } } if (leftZ == 0) { cout << "leftZ : " << leftZ << "\n"; return; } while(leftZ < pow(2, N)) { N--; divisionCount++; } CubeCheckZ(N, leftZ, divisionCount, MaxX, firstCheck); } void CubeCheckX(long long BoxX, long long BoxZ, long long MaxX, long long boxY, bool firstCheck) { if (BoxX == 0) { BoxXYZ[2] -= MaxX; return; } int N = 0; for (int i = 0; i <= 20; i++) { if (BoxX < pow(2, i) || (BoxXYZ[2] < pow(2, i))) { N = i - 1; BoxX -= pow(2, N); break; } else if (BoxX == pow(2, i) || (BoxXYZ[2] == pow(2, i))) { N = i; BoxX -= pow(2, N); break; } } if (MaxX < pow(2,N)) { MaxX = pow(2, N); } CubeCheckZ(N , BoxZ, 0, MaxX, firstCheck); firstCheck = false; CubeCheckX(BoxX , BoxZ, MaxX, boxY, firstCheck); } int main() { Initializaion(); while (BoxXYZ[2] != 0) { CubeCheckX(BoxXYZ[0], BoxXYZ[1], 0, BoxXYZ[2], true); cout << BoxXYZ[2] << " \n"; } for (iter = cubeSet.begin(); iter != cubeSet.end(); iter++) { cout << "cubeNeedNumber[" << *iter << "] : " << cubeNeedNumber[*iter] << "\n"; } return 0; }
#include <iostream>
#include <set>
#include <cmath>
#include <algorithm>

using namespace std;

set<int, greater<int>> cubeSet;
set<int, greater<int>> ::iterator iter;

int cubeNumber[21] = { 0 };
int cubeNeedNumber[21] = { 0 };

long long BoxXYZ[3] = { 0 };

int type, Number = 0;

void Initializaion()
{

	cin >> BoxXYZ[0] >> BoxXYZ[1] >> BoxXYZ[2];
	
	sort(BoxXYZ, BoxXYZ + (sizeof(BoxXYZ)/sizeof(BoxXYZ[0])));
	int N = 0;
	cin >> N;
	while (N > 0)
	{
		cin >> type >> Number;
		
		cubeSet.insert(type);
		cubeNumber[type] += Number;
		N--;
	}
}

void CubeCheckZ(long long N, long long leftZ, long long divisionCount, long long MaxX, bool firstCheck)
{

	for (;leftZ >= pow(2, N);)
	{
		if (MaxX == pow(2, N) || leftZ >= pow(2, N) && firstCheck)
		{ 
			if (N == 0)
			{
				cubeNeedNumber[N] += leftZ;
				leftZ = 0;
				continue;
			}
			cubeNeedNumber[N] += pow(4, divisionCount);
			cout << "pow(4, divisionCount) : " << pow(4, divisionCount) << "  divisionCount  :  " << divisionCount << "  N :   "<< N << "\n";
			leftZ -= pow(2, N);
			continue;
		}

		if (leftZ >= pow(2, N) && !firstCheck)
		{
			if (N == 0)
			{
				cubeNeedNumber[N] += leftZ * MaxX / pow(2, N);
				leftZ = 0;
				continue;
			}
			cubeNeedNumber[N] += MaxX / pow(2, N);
			cout << "MaxX / pow(2, N) :  " << MaxX / pow(2, N) << "  " << MaxX << "  /  " << pow(2, N) << "\n";
			leftZ -= pow(2, N);

		}
	}

	if (leftZ == 0)
	{
		cout << "leftZ :  " << leftZ << "\n";
		return;
	}


	while(leftZ < pow(2, N))
	{
		N--;
		divisionCount++;
	}
	CubeCheckZ(N, leftZ, divisionCount, MaxX, firstCheck);
}

void CubeCheckX(long long BoxX, long long BoxZ, long long MaxX, long long boxY, bool firstCheck)
{
	if (BoxX == 0)
	{   
		BoxXYZ[2] -= MaxX;
		return;
	}

	int N = 0;
	for (int i = 0; i <= 20; i++)
	{
		if (BoxX < pow(2, i) || (BoxXYZ[2] < pow(2, i)))
		{
			N = i - 1;
			BoxX -= pow(2, N);
			break;
		}
		else if (BoxX == pow(2, i) || (BoxXYZ[2] == pow(2, i)))
		{
			N = i;
			BoxX -= pow(2, N);
			break;
		}
	}
	
	if (MaxX < pow(2,N))
	{
		MaxX = pow(2, N);
	}
	
	CubeCheckZ(N , BoxZ, 0, MaxX, firstCheck);
	firstCheck = false;
	CubeCheckX(BoxX , BoxZ, MaxX, boxY, firstCheck);
}

int main()
{
	Initializaion();
	
	while (BoxXYZ[2] != 0)
	{
		CubeCheckX(BoxXYZ[0], BoxXYZ[1], 0, BoxXYZ[2], true);
		cout << BoxXYZ[2] << " \n";
	}

	for (iter = cubeSet.begin(); iter != cubeSet.end(); iter++)
	{
		cout << "cubeNeedNumber[" << *iter << "]  : " << cubeNeedNumber[*iter] << "\n";
	}

	return 0;
}

통과된 코드

위와 같이 분할 된 박스를 다시 분할 X, Y, Z 가 0일 때까지

상자의 개수 조건에 부합하지 않으면 체크하고 -1 출력

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
//cubeMultimap 은 내림차순으로 정렬된다.
multimap<int, int, greater<int>> cubeMultimap;
//cubeMultimap 순회를 위한 반복자
multimap<int, int, greater<int>>::iterator iter;
int length, width, height;
int numberOfCubes, cnt = 0;
int tempOne, tempTwo;
bool failCheck = false;
// 조건을 초기화 해주는 함수
void Initializaion()
{
cin >> length >> width >> height >> numberOfCubes;
while (numberOfCubes > 0)
{
cin >> tempOne >> tempTwo;
cubeMultimap.insert(make_pair(pow(2, tempOne), tempTwo));
numberOfCubes--;
}
}
// 분할 정복을 위한 함수 (X, Y, Z, 반복자)
void divisionConquest(int length, int width, int height, multimap<int, int, greater<int>>::iterator iter)
{
// 만약 X, Y, Z 중에서 0이 되는 값이 있다면 리턴
if (length == 0 || width == 0 || height == 0) return;
// 분할정복 로직부분
for (;iter != cubeMultimap.end(); iter++)
{
if (iter->second != 0 && length >= iter->first && width >= iter->first && height >= iter->first)
{
iter->second--;
cnt++;
divisionConquest(iter->first, iter->first, width - (iter->first), iter);
divisionConquest(length - iter->first, height, width, iter);
divisionConquest(height - iter->first, width, iter->first, iter);
return;
}
}
// 만약 큐브의 조건이 만족하지 않는다면 실패 마킹
failCheck = true;
return;
}
int main()
{
Initializaion();
// cubeMultimap의 가장 높은 값부터 시작
iter = cubeMultimap.begin();
divisionConquest(length, width, height, iter);
// 실패 마킹이 true 면 항상 -1 출력
if (failCheck) cout << -1;
else cout << cnt; // 아니면 큐브의 개수를 출력한다.
return 0;
}
#include <iostream> #include <map> #include <cmath> using namespace std; //cubeMultimap 은 내림차순으로 정렬된다. multimap<int, int, greater<int>> cubeMultimap; //cubeMultimap 순회를 위한 반복자 multimap<int, int, greater<int>>::iterator iter; int length, width, height; int numberOfCubes, cnt = 0; int tempOne, tempTwo; bool failCheck = false; // 조건을 초기화 해주는 함수 void Initializaion() { cin >> length >> width >> height >> numberOfCubes; while (numberOfCubes > 0) { cin >> tempOne >> tempTwo; cubeMultimap.insert(make_pair(pow(2, tempOne), tempTwo)); numberOfCubes--; } } // 분할 정복을 위한 함수 (X, Y, Z, 반복자) void divisionConquest(int length, int width, int height, multimap<int, int, greater<int>>::iterator iter) { // 만약 X, Y, Z 중에서 0이 되는 값이 있다면 리턴 if (length == 0 || width == 0 || height == 0) return; // 분할정복 로직부분 for (;iter != cubeMultimap.end(); iter++) { if (iter->second != 0 && length >= iter->first && width >= iter->first && height >= iter->first) { iter->second--; cnt++; divisionConquest(iter->first, iter->first, width - (iter->first), iter); divisionConquest(length - iter->first, height, width, iter); divisionConquest(height - iter->first, width, iter->first, iter); return; } } // 만약 큐브의 조건이 만족하지 않는다면 실패 마킹 failCheck = true; return; } int main() { Initializaion(); // cubeMultimap의 가장 높은 값부터 시작 iter = cubeMultimap.begin(); divisionConquest(length, width, height, iter); // 실패 마킹이 true 면 항상 -1 출력 if (failCheck) cout << -1; else cout << cnt; // 아니면 큐브의 개수를 출력한다. return 0; }
#include <iostream>
#include <map>
#include <cmath>

using namespace std;

//cubeMultimap 은 내림차순으로 정렬된다. 
multimap<int, int, greater<int>> cubeMultimap;
//cubeMultimap 순회를 위한 반복자
multimap<int, int, greater<int>>::iterator iter;


int length, width, height;
int numberOfCubes, cnt = 0;
int tempOne, tempTwo;
bool failCheck = false;

// 조건을 초기화 해주는 함수
void Initializaion()
{
	cin >> length >> width >> height >> numberOfCubes;
	while (numberOfCubes > 0)
	{
		cin >> tempOne >> tempTwo;
		cubeMultimap.insert(make_pair(pow(2, tempOne), tempTwo));
		numberOfCubes--;
	}
}

// 분할 정복을 위한 함수 (X, Y, Z, 반복자)
void divisionConquest(int length, int width, int height, multimap<int, int, greater<int>>::iterator iter)
{
	// 만약 X, Y, Z 중에서 0이 되는 값이 있다면 리턴
	if (length == 0 || width == 0 || height == 0) return;

    // 분할정복 로직부분
	for (;iter != cubeMultimap.end(); iter++)
	{
		if (iter->second != 0 && length >= iter->first && width >= iter->first && height >= iter->first)
		{
			iter->second--;
			cnt++;
			divisionConquest(iter->first, iter->first, width - (iter->first), iter);
			divisionConquest(length - iter->first, height, width, iter);
			divisionConquest(height - iter->first, width, iter->first, iter);
			return;
		}
	}

	// 만약 큐브의 조건이 만족하지 않는다면 실패 마킹
	failCheck = true;
	return;
}


int main()
{

	Initializaion();

	// cubeMultimap의 가장 높은 값부터 시작
	iter = cubeMultimap.begin();
	divisionConquest(length, width, height, iter);

	// 실패 마킹이 true 면 항상 -1 출력
	if (failCheck) cout << -1;
	else cout << cnt; // 아니면 큐브의 개수를 출력한다.

	return 0;
}

분할 정복의 개념과 구현 방법은 몰라서 오래 고민한 문제

재귀 구현 어려웠다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다