You are on page 1of 14

Counting Boxes and Cells

Brian Beckman, 8 August 2010

Referring to the Magic-Box Problem (http://www.scribd.com/doc/35207524/Box-004), this note argues (somewhat loosely) that the
candidate algorithm in that note produces the minimum number of boxes, by comparing the algorithm to a new one here that
produces the minimum by construction. This note also has some refinements of the old algorithm, a version of the visualization
program that counts the number of boxes allocated, and some experiments with it.

Recap
Imagine beads numbered 1 to N and an unlimited supply of identical magic boxes, each with b ³ 2 cells. You may put in each cell
nothing, or one bead, or another magic box, nested.
Your task, for any N and any b, is to put all beads in one box using the smallest possible total number of boxes .

Motivation
This is a stand-in for problems about distributing distinguishable items in fixed-size recursive structures, such as b-way trees. The
most familiar instance could be LISP: almost everything is distributed in binary car-cdr structures. b-way tree algorithms usually
minimize depth or maximize balance. Here, we want to minimize container allocation.

Algorithm 1: Minimal by Construction


Here's an iterative, bottom-up technique that distributes beads without ever creating a box unless necessary, so it probably pro-
duces the absolute minimum. (A) Start with one box, at level 1, and put one bead in each cell until no empty cells remain. Now pick
any level-1 cell, (B) replace the bead currently in the cell with a new, level-2 box containing the bead, and continue putting beads in
the level-2 box until no empty cells remain. Now, move back to level-1, (C) pick another level-1 cell, and repeat (B) [that is, replace
the bead currently in the cell with a new, level-2 box containing the bead, and continue putting beads in the level-2 box until no
empty cells remain]. Repeat (C) until no empty cells remain at either level 1 or level 2. Continue iterating B and C, now just at levels
2 and 3, then 3 and 4, and so on, until you run out of beads.

Definition: Perfectly Filled Box


If the number N of beads is an (integer) power of of the box-size b, all beads fit in nested boxes with no waste. Define a perfectly
filled box as one all of whose cells contain either individual beads or perfectly filled boxes.

Algorithm 1 Greedily Produces Perfectly Filled Boxes


This algorithm greedily fills empty cells and never creates a new box unless no empty cells remain at a given level. It thus greedily
produces perfectly filled boxes. It is equivalent to the following top-down, recursive algorithm that calculates the maximum possible
number of perfectly filled boxes ahead of time, fills them, and distributes the remaining beads at the current level first and then in at
most one nested cell.
The two algorithms produce the same layout of boxes, but put the beads in the boxes in a different order.

Exercise: Mechanize Algorithm 1

Algorithm 2: Top-Down Perfectly Filled Boxes


The number of boxes, including self, in a perfectly filled box is either 1, or 1 + b, or 1 + b + b2 , and so on. The number of boxes in a
perfectly filled box with k nesting levels is thus Ibk+1 - 1M ‘ Hb - 1L.
2 CountingBoxes001.nb

Example with b = 4:

bk+1 - 1
In[1]:= nPerfectBoxesAb_, k_E := ;
b-1
nReportAb_E := TableA9k, bk+1 , nPerfectBoxes@b, kD=, 8k, 0, b + 1<E~
Prepend ~8"nestingLevels", "nBeads", "nBoxes"<;
nReport@
4D

nestingLevels nBeads nBoxes


0 4 1
1 16 5
Out[3]= 2 64 21
3 256 85
4 1024 341
5 4096 1365

Construction
Find the biggest power of b less than N and call it clumpSize. The number of clumps of size clumpSize is less than N by construc-
tion, and each clump fills a perfectly filled box. Take away most beads by putting them in multiples of clumpSize into perfectly filled
boxes. Distribute the remaining beads, which must be fewer than clumpSize, by putting as many at top level as possible and using
at most one cell for nested boxes.
Here's a mechanization of algorithm 2 that returns a pair, p = 8u, w<, of the number u of boxes used and the number w of wasted
cells.

Remove@boxCountHelper, boxCD;
boxCountHelperAn_, b_, 9u_, w_=E :=
In[4]:=

H* If the number n of beads is less than or


equal to the number b of cells in a single box, *L
If@n £ b,
H* then just return 81 box used, b-n cells wasted<. *L
81, b - n<,
H* Otherwise, nest some boxes. *L
Module@
8e, clumpSize, nPreClumps, preClumpsTotal, residualBeads<,
CountingBoxes001.nb 3

8e, clumpSize, nPreClumps, preClumpsTotal, residualBeads<,


H* Next is the largest exponent such that b^e < n. *L
e = Ceiling@Log@b, nD - 1D;
H* Next is the size of a maximal
clump that can fill a perfectly filled box. *L
clumpSize = b^e;
H* Next is the number of
clumps that fit in perfectly filled boxes. *L
nPreClumps = n~Quotient~clumpSize;
H* Next is the total number
of beads in these perfectly filled boxes. *L
preClumpsTotal = clumpSize * nPreClumps;
H* Next is the residual number of beads to distribute. *L
residualBeads = n - preClumpsTotal;
H* First, add up the number of boxes used and
cells wasted in the perfectly filled sub-boxes. *L
With@8pre = Plus žž Table@boxCountHelper@clumpSize, b, 8u, w<D,
8i, nPreClumps<D<,
H* If there are some remaining
beads to distribute: at this level: *L
If@residualBeads ¹ 0,
H* There are b -
nPreClumps empty cells remaining at this level;
If that is enough room for residualBeads beads... *L
If@residualBeads £ b - nPreClumps,
H* Put all remaining beads at this level and we're
done. The 1 accounts for the box at this level. *L
pre + 81, b - nPreClumps - residualBeads<,
H* Otherwise too many beads remain for
this level. Put as many beads as possible at
this level leaving one cell for a nested box. *L
With@8nRemainingCells = b - nPreClumps - 1<,
Hpre + 81, 0< + H* one here, no extra wasted *L
4 CountingBoxes001.nb

Hpre + 81, 0< + H* one here, no extra wasted *L


boxCountHelper@
residualBeads - nRemainingCells, b, 8u, w<DLDD,
H* The following is the other branch of the top
If. There are no residual beads. We're done. *L
pre + 8u, w< + 81, b - nPreClumps<DDDD;
boxCAn_, b_E := boxCountHelper@n, b, 80, 0<D;

Here's algorithm 2 in a version that draws boxes (crunched up, comments removed, but similar in structure):

In[7]:= Remove@boxBHelper, boxBD;


boxBHelperAn_, z_, b_E :=
If@n £ b, vhBox@False, b, Table@i + z, 8i, n<DD,
Module@
8e, clumpSize, nPreClumps, preClumpsTotal, residualBeads<,
e = Ceiling@Log@b, nD - 1D; clumpSize = b^e;
nPreClumps = n~Quotient~clumpSize;
preClumpsTotal = clumpSize * nPreClumps;
residualBeads = n - preClumpsTotal;
vhBox@OddQ@eD, b,
With@8pre = Table@boxBHelper@clumpSize,
z + Hi - 1L * clumpSize, bD, 8i, nPreClumps<D<,
If@residualBeads ¹ 0,
If@residualBeads £ b - nPreClumps,
pre~Join~Table@z + preClumpsTotal + i, 8i, residualBeads<D,
With@8nRemainingCells = b - nPreClumps - 1<,
Hpre~ Append ~ boxBHelper@residualBeads - nRemainingCells,
z + preClumpsTotal, bDL~Join~
Table@z + preClumpsTotal + residualBeads -
nRemainingCells + i, 8i, nRemainingCells<DDD, preDDDDD;
boxBAn_, b_E := boxBHelper@n, 0, bD;

In[10]:= boxDAn_, b_E := 8boxB@n, bD, boxC@n, bD<

Experiments
Box-Drawing Primitive
Draw a box vertically or horizontally containing the elements in xs and using y for empty or "wasted" cells.
CountingBoxes001.nb 5

In[11]:= vhBoxAverticalP_, b_, xs_, y_: ""E :=


Style@Grid@If@verticalP,
List ž PadRight@xs, b, yD,
ListžPadRight@xs, b, yDD, Frame ® AllD, TinyD
If you have Mathematica, here is an interactive gadget:

Manipulate@boxD@Flooržn, bD,
8b, 2, 10, 1<, 8e, 3, 10, 1<, 8n, 0, b^e, 1<D
In[12]:=

n
Out[12]=

1 2 3 4

: , 86, 1<>
5 6 7 8
17 18
9 10 11 12

13 14 15 16

Some unit tests


No waste in the binary case, number of boxes one fewer than the number of beads.
6 CountingBoxes001.nb

In[13]:= 8boxD@ð, 2D< & ž Range@12, 16D

1 2 5 6

: , 811, 0<>
3 4 7 8

9 10

11 12

1 2 5 6

: , 812, 0<>
3 4 7 8

9 10
13
11 12

1 2 5 6

: , 813, 0<>
3 4 7 8

Out[13]=
9 10
13 14
11 12

1 2 5 6

: , 814, 0<>
3 4 7 8

9 10 13 14

11 12 15

1 2 5 6

: , 815, 0<>
3 4 7 8

9 10 13 14

11 12 15 16

Base 3; Waste is never more than 1 once we get started.

In[14]:= boxD@ð, 3D & ž Range žž 80, 19<

81, 3<
1 81, 2<
1 2 81, 1<
1 2 3 81, 0<

82, 1<
1 2 3

4
CountingBoxes001.nb 7

82, 0<
1 2 3

4
5

83, 1<
1 2 3

4 5 6

83, 0<
1 2 3

4 5 6

1 2 3

4 5 6 84, 1<
7 8

1 2 3

4 5 6 84, 0<
7 8 9

1 2 3

4 5 6 10 85, 1<
7 8 9

1 2 3

4 5 6 10 11 85, 0<
7 8 9

Out[14]=
1 2 3

4 5 6 10 11 12 86, 1<
7 8 9

1 2 3

4 5 6 10 11 12 13 86, 0<
7 8 9

1 2 3

87, 1<
10 11 12
4 5 6 14
13
7 8 9

1 2 3

87, 0<
10 11 12
4 5 6 15
13

7 8 9 14

1 2 3

88, 1<
10 11 12

4 5 6 16
13 14 15

7 8 9
8 CountingBoxes001.nb

1 2 3

88, 0<
10 11 12

4 5 6 13 14 15 17

7 8 9 16

1 2 3 10 11 12

4 5 6 13 14 15 89, 1<
7 8 9 16 17 18

1 2 3 10 11 12

4 5 6 13 14 15 19 89, 0<
7 8 9 16 17 18

In[15]:= boxD@ð, 4D & ž Range@2, 49D

1 2 81, 2<
1 2 3 81, 1<
1 2 3 4 81, 0<

82, 2<
1 2 3 4

1 2 3 4

5 82, 1<
6

1 2 3 4

5 82, 0<
6
7

1 2 3 4

5 6 7 8 83, 2<

1 2 3 4

5 6 7 8 83, 1<
9

1 2 3 4

5 6 7 8
83, 0<
9
10

1 2 3 4

84, 2<
5 6 7 8

9 10

11
CountingBoxes001.nb 9

11

1 2 3 4

84, 1<
5 6 7 8

9 10 11 12

1 2 3 4

84, 0<
5 6 7 8

9 10 11 12

13

1 2 3 4

85, 2<
5 6 7 8

9 10 11 12

13 14

1 2 3 4

85, 1<
5 6 7 8

9 10 11 12

13 14 15

1 2 3 4

85, 0<
5 6 7 8

9 10 11 12

13 14 15 16

1 2 3 4

86, 2<
5 6 7 8
17
9 10 11 12

13 14 15 16

1 2 3 4

86, 1<
5 6 7 8
17 18
9 10 11 12

13 14 15 16

1 2 3 4

86, 0<
5 6 7 8
17 18 19
9 10 11 12

13 14 15 16

1 2 3 4

87, 2<
5 6 7 8
17 18 19 20
9 10 11 12

13 14 15 16

1 2 3 4
10 CountingBoxes001.nb

87, 1<
5 6 7 8
17 18 19 20 21
9 10 11 12

13 14 15 16

1 2 3 4

87, 0<
5 6 7 8
17 18 19 20 21 22
9 10 11 12

13 14 15 16

1 2 3 4
17 18 19 20

88, 2<
5 6 7 8
21 22 23
9 10 11 12

13 14 15 16

1 2 3 4
17 18 19 20

88, 1<
5 6 7 8
21 23 24
9 10 11 12 22

13 14 15 16

1 2 3 4
17 18 19 20

88, 0<
5 6 7 8
21 24 25
9 10 11 12 22
23
13 14 15 16

1 2 3 4
17 18 19 20

89, 2<
5 6 7 8
21 22 23 24 25 26
9 10 11 12

13 14 15 16

1 2 3 4
17 18 19 20

89, 1<
5 6 7 8
21 22 23 24 26 27
9 10 11 12
25
13 14 15 16

1 2 3 4
17 18 19 20
Out[15]=
89, 0<
5 6 7 8
21 22 23 24
27 28
9 10 11 12
25

13 14 15 16 26

1 2 3 4 17 18 19 20

810, 2<
5 6 7 8 21 22 23 24
28 29
9 10 11 12 25 26

13 14 15 16 27

1 2 3 4
17 18 19 20
CountingBoxes001.nb 11

1 2 3 4
17 18 19 20

810, 1<
5 6 7 8
21 22 23 24
29 30
9 10 11 12
25 26 27 28

13 14 15 16

1 2 3 4 17 18 19 20

810, 0<
5 6 7 8 21 22 23 24
30 31
9 10 11 12 25 26 27 28

13 14 15 16 29

1 2 3 4 17 18 19 20

811, 2<
5 6 7 8 21 22 23 24

9 10 11 12 25 26 27 28

13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20

811, 1<
5 6 7 8 21 22 23 24
33
9 10 11 12 25 26 27 28

13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20

811, 0<
5 6 7 8 21 22 23 24
33 34
9 10 11 12 25 26 27 28

13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20

812, 2<
5 6 7 8 21 22 23 24
33 34 35
9 10 11 12 25 26 27 28

13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20

812, 1<
5 6 7 8 21 22 23 24
33 34 35 36
9 10 11 12 25 26 27 28

13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20

812, 0<
5 6 7 8 21 22 23 24
33 34 35 36 37
9 10 11 12 25 26 27 28

13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20
33 34 35 36

813, 2<
5 6 7 8 21 22 23 24
37 38
9 10 11 12 25 26 27 28

13 14 15 16 29 30 31 32
12 CountingBoxes001.nb

1 2 3 4 17 18 19 20
33 34 35 36

813, 1<
5 6 7 8 21 22 23 24
37 39
9 10 11 12 25 26 27 28 38

13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20
33 34 35 36

813, 0<
5 6 7 8 21 22 23 24
37 40
9 10 11 12 25 26 27 28 38
39
13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20
33 34 35 36

814, 2<
5 6 7 8 21 22 23 24
37 38 39 40 41
9 10 11 12 25 26 27 28

13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20
33 34 35 36

814, 1<
5 6 7 8 21 22 23 24
37 38 39 40 42
9 10 11 12 25 26 27 28
41
13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20
33 34 35 36

814, 0<
5 6 7 8 21 22 23 24
37 38 39 40
43
9 10 11 12 25 26 27 28
41

13 14 15 16 29 30 31 32 42

1 2 3 4 17 18 19 20 33 34 35 36

815, 2<
5 6 7 8 21 22 23 24 37 38 39 40
44
9 10 11 12 25 26 27 28 41 42

13 14 15 16 29 30 31 32 43

1 2 3 4 17 18 19 20
33 34 35 36

815, 1<
5 6 7 8 21 22 23 24
37 38 39 40
45
9 10 11 12 25 26 27 28
41 42 43 44

13 14 15 16 29 30 31 32

1 2 3 4 17 18 19 20 33 34 35 36

815, 0<
5 6 7 8 21 22 23 24 37 38 39 40
46
9 10 11 12 25 26 27 28 41 42 43 44

13 14 15 16 29 30 31 32 45

1 2 3 4 17 18 19 20 33 34 35 36

816, 2<
5 6 7 8 21 22 23 24 37 38 39 40
47
9 10 11 12 25 26 27 28 41 42 43 44

13 14 15 16 29 30 31 32 45 46
CountingBoxes001.nb 13

1 2 3 4 17 18 19 20 33 34 35 36

816, 1<
5 6 7 8 21 22 23 24 37 38 39 40

9 10 11 12 25 26 27 28 41 42 43 44

13 14 15 16 29 30 31 32 45 46 47 48

1 2 3 4 17 18 19 20 33 34 35 36

816, 0<
5 6 7 8 21 22 23 24 37 38 39 40
49
9 10 11 12 25 26 27 28 41 42 43 44

13 14 15 16 29 30 31 32 45 46 47 48

In[16]:= boxD@ð, 10D & ž 8199, 200, 201, 208, 209<

1 2 3 4 5 6 7 8 9 10 101 102 103 104 105 106 107 108 109 110

11 12 13 14 15 16 17 18 19 20 111 112 113 114 115 116 117 118 119 120

21 22 23 24 25 26 27 28 29 30 121 122 123 124 125 126 127 128 129 130

31 32 33 34 35 36 37 38 39 40 131 132 133 134 135 136 137 138 139 140

822, 0<
41 42 43 44 45 46 47 48 49 50 141 142 143 144 145 146 147 148 149 150
192 193 194 195 196 197 198 199
51 52 53 54 55 56 57 58 59 60 151 152 153 154 155 156 157 158 159 160

61 62 63 64 65 66 67 68 69 70 161 162 163 164 165 166 167 168 169 170

71 72 73 74 75 76 77 78 79 80 171 172 173 174 175 176 177 178 179 180

81 82 83 84 85 86 87 88 89 90 181 182 183 184 185 186 187 188 189 190

91 92 93 94 95 96 97 98 99 100 191

1 2 3 4 5 6 7 8 9 10 101 102 103 104 105 106 107 108 109 110

11 12 13 14 15 16 17 18 19 20 111 112 113 114 115 116 117 118 119 120

21 22 23 24 25 26 27 28 29 30 121 122 123 124 125 126 127 128 129 130

31 32 33 34 35 36 37 38 39 40 131 132 133 134 135 136 137 138 139 140

823, 8<
41 42 43 44 45 46 47 48 49 50 141 142 143 144 145 146 147 148 149 150

51 52 53 54 55 56 57 58 59 60 151 152 153 154 155 156 157 158 159 160

61 62 63 64 65 66 67 68 69 70 161 162 163 164 165 166 167 168 169 170

71 72 73 74 75 76 77 78 79 80 171 172 173 174 175 176 177 178 179 180

81 82 83 84 85 86 87 88 89 90 181 182 183 184 185 186 187 188 189 190

91 92 93 94 95 96 97 98 99 100 191 192 193 194 195 196 197 198 199 200

1 2 3 4 5 6 7 8 9 10 101 102 103 104 105 106 107 108 109 110

11 12 13 14 15 16 17 18 19 20 111 112 113 114 115 116 117 118 119 120

21 22 23 24 25 26 27 28 29 30 121 122 123 124 125 126 127 128 129 130

31 32 33 34 35 36 37 38 39 40 131 132 133 134 135 136 137 138 139 140

823, 7<
41 42 43 44 45 46 47 48 49 50 141 142 143 144 145 146 147 148 149 150
Out[16]= 201
51 52 53 54 55 56 57 58 59 60 151 152 153 154 155 156 157 158 159 160

61 62 63 64 65 66 67 68 69 70 161 162 163 164 165 166 167 168 169 170
14 CountingBoxes001.nb
Out[16]=

71 72 73 74 75 76 77 78 79 80 171 172 173 174 175 176 177 178 179 180

81 82 83 84 85 86 87 88 89 90 181 182 183 184 185 186 187 188 189 190

91 92 93 94 95 96 97 98 99 100 191 192 193 194 195 196 197 198 199 200

1 2 3 4 5 6 7 8 9 10 101 102 103 104 105 106 107 108 109 110

11 12 13 14 15 16 17 18 19 20 111 112 113 114 115 116 117 118 119 120

21 22 23 24 25 26 27 28 29 30 121 122 123 124 125 126 127 128 129 130

31 32 33 34 35 36 37 38 39 40 131 132 133 134 135 136 137 138 139 140

823, 0<
41 42 43 44 45 46 47 48 49 50 141 142 143 144 145 146 147 148 149 150
201 202 203 204 205 206 207 208
51 52 53 54 55 56 57 58 59 60 151 152 153 154 155 156 157 158 159 160

61 62 63 64 65 66 67 68 69 70 161 162 163 164 165 166 167 168 169 170

71 72 73 74 75 76 77 78 79 80 171 172 173 174 175 176 177 178 179 180

81 82 83 84 85 86 87 88 89 90 181 182 183 184 185 186 187 188 189 190

91 92 93 94 95 96 97 98 99 100 191 192 193 194 195 196 197 198 199 200

1 2 3 4 5 6 7 8 9 10 101 102 103 104 105 106 107 108 109 110

11 12 13 14 15 16 17 18 19 20 111 112 113 114 115 116 117 118 119 120

21 22 23 24 25 26 27 28 29 30 121 122 123 124 125 126 127 128 129 130

31 32 33 34 35 36 37 38 39 40 131 132 133 134 135 136 137 138 139 140

824, 8<
41 42 43 44 45 46 47 48 49 50 141 142 143 144 145 146 147 148 149 150
201 202 203 204 205 206 207 208 209
51 52 53 54 55 56 57 58 59 60 151 152 153 154 155 156 157 158 159 160

61 62 63 64 65 66 67 68 69 70 161 162 163 164 165 166 167 168 169 170

71 72 73 74 75 76 77 78 79 80 171 172 173 174 175 176 177 178 179 180

81 82 83 84 85 86 87 88 89 90 181 182 183 184 185 186 187 188 189 190

91 92 93 94 95 96 97 98 99 100 191 192 193 194 195 196 197 198 199 200

Conjecture
Waste is never more than b - 2.

You might also like