龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > web编程 > php编程 >

php解决装箱问题

时间:2014-07-22 14:49来源: 作者: 点击:
分享到:
我对装箱问题,石头过河问题的解法见http://www.oschina.net/question/117304_112681实现思路主要为:1. 大块石头必须优先装箱(早装和留到后面装都要装,先解决之)2. 优先装重量接近w的3. 同样
我对装箱问题,石头过河问题的解法
见http://www.oschina.net/question/117304_112681

实现思路主要为:
1. 大块石头必须优先装箱(早装和留到后面装都要装,先解决之)
2. 优先装重量接近w的
3. 同样重量优先装多块,如装9,6和装9,5,1比,则优先951装箱
4. 使用php的函数以简化代码,并使用根据k值生成函数的技巧
5. 此类问题由于本身性质,计算量较大,请酌情设置参数测试。

示例输出:(当rocks为1~9,w为15,k为3)
寻找由 3 个元素组成的最大解:
Array
(
[0] => 9
[1] => 5
[2] => 1
)

寻找由 2 个元素组成的最大解:
Array
(
[0] => 9
[1] => 6
)

寻找由 1 个元素组成的最大解:
Array
(
[0] => 9
)

寻找由 3 个元素组成的最大解:
Array
(
[0] => 8
[1] => 4
[2] => 3
)

寻找由 2 个元素组成的最大解:
Array
(
[0] => 8
[1] => 7
)

寻找由 1 个元素组成的最大解:
Array
(
[0] => 8
)

寻找由 3 个元素组成的最大解:
Array
(
[0] => 7
[1] => 6
[2] => 2
)

寻找由 2 个元素组成的最大解:
Array
(
[0] => 7
[1] => 6
)

寻找由 1 个元素组成的最大解:
Array
(
[0] => 7
)

最小次数:3
装船过程:Array
(
[0] => Array
(
[0] => 9
[1] => 5
[2] => 1
)

[1] => Array
(
[0] => 8
[1] => 4
[2] => 3
)

[2] => Array
(
[0] => 7
[1] => 6
[2] => 2
        )

)
<?php
// php 练习 之装箱问题 
// author: mx (http://my.oschina.net/meikaiyuan)
// 2013/5/30

// 问题:
// http://www.oschina.net/question/117304_112681
/*
题目:

 以前问过类似问题,没有很好解答。所以想再问一次。

有大大小小的一堆石头要用船拉到河对岸
--石头有m块,每块的重量已知
--船每次只能装k块石头,并且装载重量不可以超过w
--想求出最少几趟能把全部石头运过河。

 ------------------------------------
例1
 石头有9块,重量分别是1,2,3,4,5,6,7,8,9 
k=3 
w=15 
那么结果是,最少3次就可以运完。
 ------------------------------------
 例2
 石头有9块,重量分别是1,1,1,5,6,6,7,9,9
k=3 
w=15 
那么结果是,最少 4 次才可以运完。
*/

//代码开始

//石头
global $rocks;
// 船每次最多装几块
global $k;
// 船最大载重量
global $w;

$k=3;
$rocks=array(1,2,3,4,5,6,7,8,9);
// $rocks=array(1,1,1,5,6,6,7,9,9); //换成这组数据试试结果?
$w=15;

// 当前运了几次
$count=0;
// 运输过程,二维数组,形如 1=>array(9,5,1),表示第几次运了哪一些
$process=array();

// 求数组$rocks中一组合,使得最多$k个元素且这些元素的和尽可能大但小于等于指定值$w, 数组已经按从大到小排序过
function getMaxCombination( ) {
    //石头
	global $rocks;
	// 船每次最多装几块
	global $k;
	// 船最大载重量
	global $w;

	// 保存各种$k下满足所有元素之和小于等于w且最大的集合
	$k_w_result=array();
	// 最大组合值
	$max_sum=0;
	// 哪项最大
	$max_one=0;
	
	for ($start=$k;$start>0;$start--){  
		// 找到由固定$start个元素组成的最大解
		$start_w_arr = getMaxCombination2($start);
		echo "寻找由 $start 个元素组成的最大解: \n";
		print_r($start_w_arr);
		echo "\n";
		$sum=array_sum( $start_w_arr );
		// 注意:因为是降序排列的,$k--, 越早找到的同sum的组合$k越大,也就是解越好,所以是小于不是小于等于
		if($sum>$max_sum){
			$max_sum=$sum;
			$max_one=$k-$start;
		}
		$k_w_result[]= $start_w_arr ;
	}
	return $k_w_result[$max_one];
}

// 求数组$rocks中一由给定$start个元素构成的组合,这些元素的和尽可能大但小于等于指定值$w, 数组已经按从大到小排序过
function getMaxCombination2($start ) { 
    //石头们
	global $rocks;
	// 船每次最多装几块
	global $k;
	// 船最大载重量
	global $w;

	if(count($rocks)<$start){
			return array(0);
	}
	$c=count($rocks); 
	//  根据$start生成一函数,内含$start层for循环代码, 然后包含进来再调用此函数
		if(!file_exists( "$start.php")){
		$output_1="";
		$output_2='$sum=';
		$output_3='if($sum<=$w){ $arr=array(); ';
		$output_4='';
		for($i=0;$i<$start;$i++){
			$output_1.='for($p'.$i.'='.$i.';$p'.$i.'<$c-'.($start-$i-1).';$p'.$i.'++){'."\n";
			if($i>0){
				$output_2.='+';
			}
			$output_2.='$rocks[$p'.$i.']';
			$output_3.='$arr[]=$rocks[$p'.$i.'];';
			$output_4.='}';
		}
		$output_2.=';';
		$output_3.=' return $arr; }' ;
		$output='<?php function myfor'.$start.'($rocks,$c,$w){ '.$output_1.$output_2.$output_3.$output_4 .' } ?>';
		
		file_put_contents("$start.php",$output);
		include_once "$start.php";
		}
		else{
			include_once "$start.php";
		}
	return call_user_func('myfor'.$start ,$rocks,$c,$w);
}

//开始计算
// 数组先从大到小排序, 此操作是后续算法省时省力的关键
rsort($rocks);

// 为了防止石头过大船过小造成下面算法死循环
foreach ($rocks as $v){
	if($v>$w){
		die("有石头不可能装船,换大船来再战!");
	}
}

// 算法开始
while(!empty($rocks)){
	// 开始装一船
	$process[$count]=array();

	// 装船 
	$process[$count]= getMaxCombination( ) ;
	
	// 从石头中移除已经装船的
	foreach($process[$count] as $v){
				$key=array_search($v, $rocks);
				unset( $rocks[$key]);
	}
	$rocks=array_values($rocks);
	// 装船数+1
	$count++;
}
// 输出结果
echo '最小次数:'.$count."\n";

echo '装船过程:';
print_r($process);

?>
精彩图集

赞助商链接