here something unsophisticated unoptimal but easy as a start point
- Based on mine comments
- exploiting common container size 480px
Algorithm:
- rotate all containers (bins) to get 480 height
- sort bins by width after rotation descending
- need ceil(1080/480)=3 lines of 480px bins
use the widest bins to fill all the lines but never crossing 1920px
- they are sorted so use the first ones
- all used ones mark as used
- use only unused bins
arrange rest of the bins to lines (goes to the shortest line)
- so take unused bins
- determine which line is shortest
- if the shortest line is already 1920px wide or more then stop
- if not move the bin to that line and mark it as used
C++ source code (ugly static allocation but simple and no lib used):
//---------------------------------------------------------------------------
struct _rec { int x,y,xs,ys,_used; };
_rec bin[128],item; int bins=0;
//---------------------------------------------------------------------------
void bin_generate(int n) // generate problem
{
int i;
Randomize();
item.x=0;
item.y=0;
item.xs=1920;
item.ys=1080;
for (bins=0;bins<n;bins++)
{
bin[bins].x=0;
bin[bins].y=0;
i=Random(2);
if (i==0) { bin[bins].xs=320; bin[bins].ys=480; }
else if (i==1) { bin[bins].xs=480; bin[bins].ys=800; }
else i=i;
// if (i==2) { bin[bins].xs=1920; bin[bins].ys=1080; }
}
}
//---------------------------------------------------------------------------
void bin_solve() // try to solve problem
{
int i,e,n,x,y,x0[128],y0[128],common=480;
_rec *r,*s,t;
// rotate bins to ys=480
for (r=bin,i=0;i<bins;i++,r++) if (r->xs==common) { x=r->xs; r->xs=r->ys; r->ys=x; }
// sort bins by xs desc
for (e=1;e;) for (e=0,r=bin,s=r+1,i=1;i<bins;i++,r++,s++) if (r->xs<s->xs) { t=*r; *r=*s; *s=t; e=1; }
// prepare lines needed ... n is num of lines, _rest is one common side height line is needed to add
n=item.ys/common; if (item.ys%common) n++; item.x=0; item.y=0;
for (i=0;i<n;i++) { x0[i]=0; y0[i]=common*i; }
for (r=bin,i=0;i<bins;i++,r++) r->_used=0;
// arrange wide bins to lines
for (e=0;e<n;e++)
for (r=bin,i=0;i<bins;i++,r++)
if (!r->_used)
if (x0[e]+r->xs<=item.xs)
{
r->x=x0[e];
r->y=y0[e];
r->_used=1;
x0[e]+=r->xs;
if (x0[e]>=item.xs) break;
}
// arrange rest bins to lines (goes to the shortest line)
for (r=bin,i=0;i<bins;i++,r++)
if (!r->_used)
{
// find shortest line
for (e=0,x=0;x<n;x++) if (x0[e]>x0[x]) e=x;
// stop if shortest line is already wide enough
if (x0[e]>=item.xs) break;
// fit the bin in it
r->x=x0[e];
r->y=y0[e];
r->_used=1;
x0[e]+=r->xs;
}
// arrange the unused rest below
for (x=0,y=n*common+40,r=bin,i=0;i<bins;i++,r++) if (!r->_used) { r->x=x; r->y=y; x+=r->xs; }
}
//---------------------------------------------------------------------------
Usage:
bin_generate(7); // generate n random devices to bin[bins] array of rectangles
bin_solve(); // try to solve problem ... just rearrange the bin[bins] values

- this is not optimal but with some tweaks could be enough
- for example last 2 lines need 600px of height together so if you have devices at that size or closely larger you can use them to fill the 2 last lines as 1 line ...
- if not then may be some graph or tree approach will be better (due to low container count)
[Edit1] universal sizes
when you have not guarantied fixed common container size then you have to compute it instead...
//---------------------------------------------------------------------------
struct _rec { int x,y,xs,ys,_used; _rec(){}; _rec(_rec& a){ *this=a; }; ~_rec(){}; _rec* operator = (const _rec *a) { *this=*a; return this; }; /*_rec* operator = (const _rec &a) { ...copy... return this; };*/ };
List<_rec> bin,bintype;
_rec item;
//---------------------------------------------------------------------------
void bin_generate(int n) // generate problem
{
int i;
_rec r;
Randomize();
// target resolution
item.x=0; item.xs=1920;
item.y=0; item.ys=1080;
// all used device sizes in portrait start orientation
bintype.num=0; r.x=0; r.y=0; r._used=0;
r.xs= 320; r.ys= 480; bintype.add(r);
r.xs= 480; r.ys= 800; bintype.add(r);
r.xs= 540; r.ys= 960; bintype.add(r);
// r.xs=1080; r.ys=1920; bintype.add(r);
// create test case
bin.num=0; for (i=0;i<n;i++) bin.add(bintype[Random(bintype.num)]);
}
//---------------------------------------------------------------------------
void bin_solve() // try to solve problem
{
int i,j,k,e,x,y;
_rec *r,s;
List<int> hsiz,hcnt; // histogram of sizes
List< List<int> > lin; // line of bins with common size
// compute histogram of sizes
hsiz.num=0; hcnt.num=0;
for (r=bin.dat,i=0;i<bin.num;i++,r++)
{
x=r->xs; for (j=0;j<hsiz.num;j++) if (x==hsiz[j]) { hcnt[j]++; j=-1; break; } if (j>=0) { hsiz.add(x); hcnt.add(1); }
x=r->ys; for (j=0;j<hsiz.num;j++) if (x==hsiz[j]) { hcnt[j]++; j=-1; break; } if (j>=0) { hsiz.add(x); hcnt.add(1); }
}
// sort histogram by cnt desc (most occurent sizes are first)
for (e=1;e;) for (e=0,j=0,i=1;i<hsiz.num;i++,j++) if (hcnt[j]<hcnt[i])
{
x=hsiz[i]; hsiz[i]=hsiz[j]; hsiz[j]=x;
x=hcnt[i]; hcnt[i]=hcnt[j]; hcnt[j]=x; e=1;
}
// create lin[][]; with ys as common size (separate/rotate bins with common sizes from histogram)
lin.num=0;
for (r=bin.dat,i=0;i<bin.num;i++,r++) r->_used=0;
for (i=0;i<hsiz.num;i++)
{
lin.add(); lin[i].num=0; x=hsiz[i];
for (r=bin.dat,j=0;j<bin.num;j++,r++)
{
if ((!r->_used)&&(x==r->xs)) { lin[i].add(j); r->_used=1; y=r->xs; r->xs=r->ys; r->ys=y; }
if ((!r->_used)&&(x==r->ys)) { lin[i].add(j); r->_used=1; }
}
}
for (i=0;i<lin.num;i++) if (!lin[i].num) { lin.del(i); i--; }
// sort lin[][] by xs desc (widest bins are first)
for (i=0;i<lin.num;i++)
for (e=1;e;) for (e=0,k=0,j=1;j<lin[i].num;j++,k++)
if (bin[lin[i][k]].xs<bin[lin[i][j]].xs)
{ s=bin[lin[i][j]]; bin[lin[i][j]]=bin[lin[i][k]]; bin[lin[i][k]]=s; e=1; }
// arrange lines to visually check previous code (debug) ... and also compute the total line length (width)
for (y=item.ys+600,i=0;i<lin.num;i++,y+=r->ys) for (x=0,j=0;j<lin[i].num;j++) { r=&bin[lin[i][j]]; r->x=x; r->y=y; x+=r->xs; }
for (i=0;i<lin.num;i++)
{
j=lin[i][lin[i].num-1]; // last bin in line
hsiz[i]=bin[j].x+bin[j].xs; // total width
hcnt[i]=bin[j].ys; // line height
}
// now compute solution
for (r=bin.dat,i=0;i<bin.num;i++,r++) r->_used=0; // reset usage first
for (y=0,k=1,i=0;i<lin.num;i++) // process lines with common size
while(hsiz[i]>=item.xs) // stop if line shorter then needed
{
x=0;
// arrange wide bins to line
for (j=0;j<lin[i].num;j++)
{
r=&bin[lin[i][j]];
if ((!r->_used)&&(x+r->xs<=item.xs))
{
r->x=x; hsiz[i]-=x; x+=r->xs;
r->y=y; r->_used=k;
if (x>=item.xs) break;
}
}
// arrange short bins to finish line
if (x<item.xs)
for (j=lin[i].num-1;j>=0;j--)
{
r=&bin[lin[i][j]];
if (!r->_used)
{
r->x=x; hsiz[i]-=x; x+=r->xs;
r->y=y; r->_used=k;
if (x>=item.xs) break;
}
}
// remove unfinished line
if (x<item.xs)
{
for (j=0;j<lin[i].num;j++)
{
r=&bin[lin[i][j]];
if (r->_used==k)
{
r->x=0; r->y=0;
r->_used=0;
hsiz[i]+=r->xs;
}
}
break;
}
// next line
y+=hcnt[i];
if (y>=item.ys) break; // solution found already?
}
// rotate unused rest to have ys>=as needed but as wide as can be to form last line
e=item.ys-y; x=0;
if (e>0) for (r=bin.dat,i=0;i<bin.num;i++,r++)
if (!r->_used)
{
if ((r->xs<e)&&(r->ys<e)) continue; // skip too small bins
if (r->xs<r->ys) { j=r->xs; r->xs=r->ys; r->ys=j; }
if (r->ys< e) { j=r->xs; r->xs=r->ys; r->ys=j; }
r->x=x; x+=r->xs;
r->y=y; r->_used=1;
}
}
//---------------------------------------------------------------------------
- it is almost the same as before but prior to solution histogram of container sizes is computed
- choose most occurent ones and form groups of compatible bins (containers)
- then apply the algorithm ...
- I added usage of dynamic array template
List<> because on static allocation I would go mad before writing this ...
List<int> x; is the same as int x[];
x.num is the number of items inside x[]
x.add() adds new item to end of x[]
x.add(q) adds new item = q to end of x[]
x.del(i) deletes i-th item from x[] ... indexing is from zero
- so rewrite to what ever you use instead ...
List< List<int> > y; is 2D array y[][] ...
- at last form last line from unused bins ...
- This is not robust nor safe but it mostly works (it need some tweaking but I am too lazy for that)
- the solution depends also on the input set order so you can find more solutions for the same input set if you shuffle it a bit ... (if some common sizes has the same count)

bin packingproblem How many containers there will be used?