<?php
/*
* Created on 11.08.2011 by Sergey Fedorenko
*/
class Cutter {
public $the_best_tail;
private $m_units = array();
public $m_best_units = array();
public $m_best_tails = array();
public $m_best_result;
public $m_best_store=array();
public $m_best_store_tail=array();
public $a_best_result;
public $a_best_store=array();
public $a_best_store_tail=array();
public function SetStore($store) { $this->m_store=$store; }
public function SetUnits($units) { $this->m_units=$units; }
public function SwapUnits($key1,$key2) { $tmp=$this->m_units[$key1]; $this->m_units[$key1]=$this->m_units[$key2]; $this->m_units[$key2]=$tmp; }
public function Review() {
// echo "\n-------"; foreach($this->m_units as $k => $val) {echo $val." ";} echo "-------";
$m_units_used=array_fill ( 0 , count($this->m_units), 0 );
$num_units=count($this->m_units);
$summ_tails=0;
$index_result=0;
do {
$best_tail=1000000;
foreach ($this->m_store as $s_key => $s_value) {
$tail=$s_value;
$temp_units_used=$m_units_used;
foreach ($this->m_units as $u_key => $u_value) {
if($m_units_used[$u_key]==1) continue;
if($tail>$u_value) {
$tail-=$u_value;
$temp_units_used[$u_key]=1;
}
}
if($tail<$best_tail) {
$best_tail=$tail;
$best_storekey=$s_key;
$best_units_used=$temp_units_used;
$this->m_best_store[$index_result]=$this->m_store[$s_key];
$add_index=0;
unset($this->m_best_result[$index_result]);
// echo "\n".$index_result." Best:".$this->m_store[$s_key]." tail:".$tail;
foreach ($this->m_units as $u_key => $u_value) {
if($temp_units_used[$u_key]==$m_units_used[$u_key] || $temp_units_used[$u_key]!=1) continue;
$this->m_best_result[$index_result][$add_index]=$u_value;
// echo " ".$u_value;
$add_index++;
}
$this->m_best_store_tail[$index_result]=$tail;
}
}
//нашли лучший вариант (какую из заготовок брать)
$m_units_used=$best_units_used;
$summ_tails+=$best_tail;
$last_tail=$best_tail;
// echo "\n----------".array_sum($m_units_used)."<".$num_units;
$index_result++;
}
while(array_sum($m_units_used)<$num_units);
return $summ_tails-$last_tail;
}
public function FindTheBest( $limit_iterations) {
rsort($this->m_units,SORT_NUMERIC);
$u_len=count($this->m_units);
$this->the_best_tail=1000000000;
for( $iter=0; $iter<$limit_iterations; $iter++) {
unset($this->m_best_result);
unset($this->m_best_store);
unset($this->m_best_store_tail);
$this_tail=$this->Review();
if($this_tail<$this->the_best_tail) {
$this->the_best_tail=$this_tail;
$this->a_best_result =$this->m_best_result;
$this->a_best_store =$this->m_best_store;
$this->a_best_store_tail=$this->m_best_store_tail;
}
shuffle($this->m_units);
//$this->SwapUnits(rand(0,$u_len-1),rand(0,$u_len-1));
}
}
}
//--------------- how to use -----------------
// $detal = array(56,151,234,387,4729,587,46,1568,823,214,765,2634,1845,1733,936,631,1936,2190,2184,1439,56,151,234,387,4729,587,46,1568,823,214,765,2634,1845,1733,936,631,1936,2190,2184,1439);
$zagot = array(3000, 6000);
$detal = array(56,151,234,387,4729,587,46,1568,823,214,765,2634,1845,1733,936,631,1936,2190,2184,1439);
$the_cutter=new Cutter();
$the_cutter->SetStore($zagot);
$the_cutter->SetUnits($detal);
$the_cutter->FindTheBest(1000);
foreach($the_cutter->a_best_store as $i => $val) {
echo "\n Заготовка:".$val." ( ";
foreach( $the_cutter->a_best_result[$i] as $unit) {
echo $unit." ";
}
echo ") Остаток:".$the_cutter->a_best_store_tail[$i];
}
echo "\nСуммарный остаток (без последнего):".$the_cutter->the_best_tail;
?>
/*
* Created on 11.08.2011 by Sergey Fedorenko
*/
class Cutter {
public $the_best_tail;
private $m_units = array();
public $m_best_units = array();
public $m_best_tails = array();
public $m_best_result;
public $m_best_store=array();
public $m_best_store_tail=array();
public $a_best_result;
public $a_best_store=array();
public $a_best_store_tail=array();
public function SetStore($store) { $this->m_store=$store; }
public function SetUnits($units) { $this->m_units=$units; }
public function SwapUnits($key1,$key2) { $tmp=$this->m_units[$key1]; $this->m_units[$key1]=$this->m_units[$key2]; $this->m_units[$key2]=$tmp; }
public function Review() {
// echo "\n-------"; foreach($this->m_units as $k => $val) {echo $val." ";} echo "-------";
$m_units_used=array_fill ( 0 , count($this->m_units), 0 );
$num_units=count($this->m_units);
$summ_tails=0;
$index_result=0;
do {
$best_tail=1000000;
foreach ($this->m_store as $s_key => $s_value) {
$tail=$s_value;
$temp_units_used=$m_units_used;
foreach ($this->m_units as $u_key => $u_value) {
if($m_units_used[$u_key]==1) continue;
if($tail>$u_value) {
$tail-=$u_value;
$temp_units_used[$u_key]=1;
}
}
if($tail<$best_tail) {
$best_tail=$tail;
$best_storekey=$s_key;
$best_units_used=$temp_units_used;
$this->m_best_store[$index_result]=$this->m_store[$s_key];
$add_index=0;
unset($this->m_best_result[$index_result]);
// echo "\n".$index_result." Best:".$this->m_store[$s_key]." tail:".$tail;
foreach ($this->m_units as $u_key => $u_value) {
if($temp_units_used[$u_key]==$m_units_used[$u_key] || $temp_units_used[$u_key]!=1) continue;
$this->m_best_result[$index_result][$add_index]=$u_value;
// echo " ".$u_value;
$add_index++;
}
$this->m_best_store_tail[$index_result]=$tail;
}
}
//нашли лучший вариант (какую из заготовок брать)
$m_units_used=$best_units_used;
$summ_tails+=$best_tail;
$last_tail=$best_tail;
// echo "\n----------".array_sum($m_units_used)."<".$num_units;
$index_result++;
}
while(array_sum($m_units_used)<$num_units);
return $summ_tails-$last_tail;
}
public function FindTheBest( $limit_iterations) {
rsort($this->m_units,SORT_NUMERIC);
$u_len=count($this->m_units);
$this->the_best_tail=1000000000;
for( $iter=0; $iter<$limit_iterations; $iter++) {
unset($this->m_best_result);
unset($this->m_best_store);
unset($this->m_best_store_tail);
$this_tail=$this->Review();
if($this_tail<$this->the_best_tail) {
$this->the_best_tail=$this_tail;
$this->a_best_result =$this->m_best_result;
$this->a_best_store =$this->m_best_store;
$this->a_best_store_tail=$this->m_best_store_tail;
}
shuffle($this->m_units);
//$this->SwapUnits(rand(0,$u_len-1),rand(0,$u_len-1));
}
}
}
//--------------- how to use -----------------
// $detal = array(56,151,234,387,4729,587,46,1568,823,214,765,2634,1845,1733,936,631,1936,2190,2184,1439,56,151,234,387,4729,587,46,1568,823,214,765,2634,1845,1733,936,631,1936,2190,2184,1439);
$zagot = array(3000, 6000);
$detal = array(56,151,234,387,4729,587,46,1568,823,214,765,2634,1845,1733,936,631,1936,2190,2184,1439);
$the_cutter=new Cutter();
$the_cutter->SetStore($zagot);
$the_cutter->SetUnits($detal);
$the_cutter->FindTheBest(1000);
foreach($the_cutter->a_best_store as $i => $val) {
echo "\n Заготовка:".$val." ( ";
foreach( $the_cutter->a_best_result[$i] as $unit) {
echo $unit." ";
}
echo ") Остаток:".$the_cutter->a_best_store_tail[$i];
}
echo "\nСуммарный остаток (без последнего):".$the_cutter->the_best_tail;
?>
Вот результат работы программы:
Заготовка:6000 ( 56 1936 1439 214 2190 151 ) Остаток:14
Заготовка:6000 ( 2634 765 1568 936 46 ) Остаток:51
Заготовка:6000 ( 1733 2184 1845 234 ) Остаток:4
Заготовка:6000 ( 823 4729 387 ) Остаток:61
Заготовка:6000 ( 587 631 ) Остаток:4782
Суммарный остаток (без последнего):130
Заготовка:6000 ( 2634 765 1568 936 46 ) Остаток:51
Заготовка:6000 ( 1733 2184 1845 234 ) Остаток:4
Заготовка:6000 ( 823 4729 387 ) Остаток:61
Заготовка:6000 ( 587 631 ) Остаток:4782
Суммарный остаток (без последнего):130
Время работы — меньше секунды на 1000 вариантах
#1 by Станислав on 28.08.2012 - 19:44
Добрый вечер! Как с вами связаться? Напишите, пожалуйста, на мою почту. Есть дело относительно этого алгоритма.
#2 by MichaelCH on 08.03.2016 - 15:25
Указанные исходные данные можно раскроить лучше:
Заготовка:6000 ( 234 4729 823 214 ) Остаток:0
Заготовка:6000 ( 46 1845 1733 936 1439 ) Остаток:1
Заготовка:6000 ( 56 1568 2190 2184 ) Остаток:2
Заготовка:6000 ( 765 2634 631 1936 ) Остаток:34
Заготовка:6000 ( 151 387 587 ) Остаток:4875
Суммарный остаток (без последнего):37
Если взять деталей в два раза больше (как в закомментированном коде), то суммарные отходы, вообще минимальны:
Заготовка:6000 ( 234 4729 823 214 ) Остаток:0
Заготовка:6000 ( 234 4729 823 214 ) Остаток:0
Заготовка:6000 ( 151 151 387 1936 1936 1439 ) Остаток:0
Заготовка:6000 ( 56 46 765 765 2634 1733 ) Остаток:1
Заготовка:6000 ( 46 1845 1733 936 1439 ) Остаток:1
Заготовка:6000 ( 387 1568 1568 1845 631 ) Остаток:1
Заготовка:6000 ( 587 587 2634 2190 ) Остаток:2
Заготовка:6000 ( 56 936 631 2190 2184 ) Остаток:3
Заготовка:6000 ( 2184 ) Остаток:3816
Суммарный остаток (без последнего):8