das ist mal 'ne wirklich interessante frage
ich meine, dass das problem kaum 'sauber' zu lösen ist - es lässt sich auf andere problemstellungen zurückführen, an die ich mich als NP-vollständig erinnere - da gab es mal ein typisches problem, das ähnlich ist:
du hast für eine universität eine liste von räumen (raumid, kapazität), und eine liste von vorlesungen (vorlesungsID, teilnehmer) - und mit diesen daten soll man eine raumbelegung konstruieren, in der die räume optimal ausgenutzt werden, d.h. möglichst wenig freie plätze in einem raum übrigbleiben, aber dass trotzdem alle teilnehmer einen platz finden. das ganze sei anscheinend eine ziemlich üble sache, das zu programmieren.
wenn man das problem aber etwas 'vereinfacht' und die anforderungen nicht so hoch stellt, ist das ganze problemlos lösbar:
PHP-Code:
<?php
/**
* a simple api for an image.
* you could change the constructor to receive a path to an image
* and retrieve the width dynamically.
* @author axo
*/
class Image {
var $w;
/**
* constructor.
* @param $w integer the width of the image.
* this could be changed to take a path to an existing image...
* @return void
* @access public
*/
function Image($w) {
$this -> w = $w;
}
/**
* returns the width of the image.
* @param void
* @return integer
* @access public
*/
function getWidth() {
return $this -> w;
}
/**
* @access public
*/
function toString() {
return '['.$this -> w . '' . str_repeat('x',$this -> w - strlen($this -> w) - 2) .']';
}
}
/**
* a row contains several images.
* it can always take at least one image.
*/
class Row {
/**
* the actual width of the row.
* this is needed in order to be able to say whether
* add() can take the image or not.
*/
var $_actualWidth;
/**
* the maximum width of the row.
*/
var $_maxWidth = 500;
/**
* contains the images.
*/
var $_images = array();
/**
* constructor.
* @param $maxWidth the maximum width of the row.
* @access public
* @return void
*/
function Row($maxWidth = 500) {
$this -> _maxWidth = $maxWidth;
}
/**
* adds an image if it does not exceed the maximum width.
* the first image can always be taken - this is
* in order to avoid infinite loops if a given image width
* is greater than the maximum width of the row.
* @param $Image Image
* @return boolean
* @access public
*/
function add($Image) {
if ($this -> _wouldExceed($Image -> getWidth())) {
return false;
}
return $this -> _doAdd($Image);
}
/**
* checks whether the addition of a given width would exceed the maximum width.
* @param $newWidth integer
* @return void
* @access private
*/
function _wouldExceed($newWidth) {
if ($this -> _actualWidth < 1) {
return false;
}
return ($this -> _actualWidth + $newWidth > $this -> _maxWidth);
}
/**
* adds the image to the own stack and updates the actual width.
* @param $Image Image
* @return boolean (always true)
* @access private
*/
function _doAdd($Image) {
$this -> _actualWidth += $Image -> getWidth();
$this -> _images[] = &$Image;
return true;
}
/**
* simple toString implementation to show the result.
* @param void
* @return string
* @access public
*/
function toString() {
$foo = "";
for ($i=0,$m=count($this -> _images);$i<$m;$i++) {
$foo .= $this -> _images[$i] -> toString();
}
$foo .= "\n".str_repeat('-',$this -> _maxWidth)."\n";
return $foo;
}
}
/**
*
*/
class RowContainer {
var $_rows = array();
var $_maxWidth = 90;
/**
* @param $max integer the maximum width of a row
* @return void
* @access public
*/
function RowContainer($max = 500) {
$this -> _maxWidth = $max;
}
/**
* builds the rows from a given array of images.
* @param $images array
* @return void
*/
function build(&$images) {
$i = 0;
$this -> _rows[0] = & new Row($this -> _maxWidth);
foreach ($images as $img) {
$row = & $this -> _rows[$i];
/* @var $row Row */
while (false === $this -> _rows[$i] -> add($img)) {
$i++;
if (!array_key_exists($i,$this -> _rows)) {
$this -> _rows[$i] = & new Row($this -> _maxWidth);
}
}
}
}
/**
* @param void
* @return string
* @access public
*/
function toString() {
$foo = "<pre style='font-family:monospace'>\n"
.'['.$this -> _maxWidth.str_repeat('x',$this -> _maxWidth - strlen($this -> _maxWidth) - 2) . ']' . "\n";
$foo .= str_repeat('-',$this -> _maxWidth) . "\n";
for ($i=0,$m=count($this -> _rows);$i<$m;$i++) {
$r = & $this -> _rows[$i];
$foo .= $r -> toString();
}
return $foo . "\n</pre>";
}
}
?>
test:
PHP-Code:
<?php
$input = array(
new Image(60),
new Image(60),
new Image(60),
new Image(70),
new Image(40),
new Image(40),
new Image(50),
new Image(120),
new Image(10),
new Image(20),
new Image(40),
new Image(60),
new Image(5),
new Image(20),
new Image(6),
new Image(60),
new Image(120),
new Image(30),
new Image(40),
new Image(60),
new Image(40),
);
$rowC = & new RowContainer(150);
$rowC -> build($input);
echo $rowC -> toString();
?>
ausgabe:
Code:
[150xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
------------------------------------------------------------------------------------------------------------------------------------------------------
[60xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx][60xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
------------------------------------------------------------------------------------------------------------------------------------------------------
[60xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx][70xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
------------------------------------------------------------------------------------------------------------------------------------------------------
[40xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx][40xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx][50xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
------------------------------------------------------------------------------------------------------------------------------------------------------
[120xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx][10xxxxxx][20xxxxxxxxxxxxxxxx]
------------------------------------------------------------------------------------------------------------------------------------------------------
[40xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx][60xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx][5xx][20xxxxxxxxxxxxxxxx][6xxx]
------------------------------------------------------------------------------------------------------------------------------------------------------
[60xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
------------------------------------------------------------------------------------------------------------------------------------------------------
[120xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx][30xxxxxxxxxxxxxxxxxxxxxxxxxx]
------------------------------------------------------------------------------------------------------------------------------------------------------
[40xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx][60xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx][40xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
------------------------------------------------------------------------------------------------------------------------------------------------------
sorry für die objekte - ich kann auf die schnelle so leichter denken ...
wie man sehen kann, ist der algorithmus nicht gerade optimal - eigentlich sollte das dreißiger-bild aus der vorletzten zeile in die drittletzte zeile verschoben werden, damit's schöner aussieht - für so eine operation würde der rechenaufwand aber wieder sehr hoch werden und man kommt nicht mit einer einzigen iteration über die bilder zum ergebnis.