/**
* 一个国王要赏赐一个大臣30枚金币,但其中有一枚是假币。国王提出要求:只能用一个天平作为测量工具,并用尽量少的比较次数找出这枚假币,
* 那么余下的29枚金币就赏赐给这个大臣;否则这个大臣将得不到赏赐。已知假币要比真币的分量略轻一些。
* 这个问题,我们可以采用分治的办法去解决,金币分成一半后没有剩余,则假币在轻的一边;如果分成两分剩余一个,
*则比较两部分,如果两个相等,则剩余的一个就是假币。如果两分中一份轻,则假币就是轻的一份中。然后在进行分治,
* 直到找到问题的答案
*/
header("Content-Type:text/html;charset=utf-8");
$findTime = 0;
/*
* 分俩组计算
*/
function getFalseCoin($coin, $low, $high)
{
$GLOBALS['findTime']++;
$tmp1 = 0;
$tmp2 = 0;
$tmp = 0;
//当比较最后两个时,判断那个值最小,返回小的那个值
if($low+1 == $high)
{
if($coin[$low] < $coin[$high])
{
return $low;
}
else
{
return $high;
}
}
//剩余硬币 个数
$tmp = $high - $low + 1;
//硬币数为偶数
if($tmp % 2 == 0){
$tmp1 = getCoinSum($coin,$low,$low+intval($tmp/2)-1);
$tmp2 = getCoinSum($coin,$low+intval($tmp/2),$high);
if($tmp1 < $tmp2)
{
return getFalseCoin($coin,$low,$low+intval($tmp/2)-1);
}
else
{
return getFalseCoin($coin,$low+intval($tmp/2),$high);
}
}
//硬币数为奇数
else
{
$tmp1 = getCoinSum($coin,$low,$low + intval($tmp/2)-1);
$tmp2 = getCoinSum($coin,$low + intval($tmp/2)+1,$high);
if($tmp1 < $tmp2)
{
return getFalseCoin($coin,$low,$low+intval($tmp/2)-1);
}
else if($tmp1>$tmp2)
{
return getFalseCoin($coin,$low+intval($tmp/2)+1,$high);
}
else
{
return $low+intval($tmp/2);
}
}
}
/*
* 分三组计算
*/
function getFalseCoin3($coin, $low, $high)
{
$GLOBALS['findTime']++;
//print_r($coin);
//echo '
';
$tmp1 = 0;
$tmp2 = 0;
$tmp3 = 0;
$tmp = 0;
//当比较最后三个时,判断那个值最小,返回小的那个值
if($low+2 == $high)
{
if($coin[$low] == $coin[$high])
{
return $low+1;
}
else if($coin[$low] < $coin[$high])
{
return $low;
}
else{
return $high;
}
}
//剩余硬币 个数
$tmp = $high - $low + 1;
//echo $high.'--';
$tmpMid= intval($tmp/3);
$tmpMod = $tmp % 3;
//echo $tmpMod.'--';
//echo $tmpMid.'
';
//余数处理
if($tmpMod==1){//余数为一
if($coin[$low]==$coin[$high]){
$high = $high-1;
$tmp = $tmp-1;
}
else if($coin[$low]<$coin[$high]){
return $low;
}
else{
return $high;
}
}
else if($tmpMod==2){//余数为二
if($coin[$high] == $coin[$high-1] ){
$high = $high-2;
$tmp = $tmp-2;
}
else if($coin[$high] > $coin[$high-1]){
return $high-1;
}
else{
return $high;
}
}
$tmp1 = getCoinSum($coin,$low,$low+$tmpMid-1);
//echo ($low) .'->'. ($low+$tmpMid-1) . '
';
$tmp2 = getCoinSum($coin,$low+$tmpMid,$low+2*$tmpMid-1);
//echo ($low+$tmpMid) .'->'. ($low+2*$tmpMid-1) . '
';
$tmp3 = getCoinSum($coin,$low+2*$tmpMid,$high);
//echo ($low+2*$tmpMid) .'->'. ($high) . '
';
if($tmp1 == $tmp2)//假币在第三组中
{
return getFalseCoin3($coin,$low+2*$tmpMid,$high);
}
else
{
if($tmp1 == $tmp3){//假币在第二组中
return getFalseCoin3($coin,$low+$tmpMid,$low+2*$tmpMid-1);
}
else{//假币在第一组中
return getFalseCoin3($coin,$low,$low+$tmpMid-1);
}
}
}
function getCoinSum($coin, $low, $high)
{
$sum = 0;
while($low <= $high){
$sum += $coin[$low++];
}
return $sum;
}
$coin = array(2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2);
print_r($coin);
echo '
分二组计算:
';
$result = getFalseCoin($coin,0,count($coin)-1);
echo '
';
echo '一共查找了:'.$findTime.'次';
echo '
';
echo '假币位于:'.$result.'处';
$findTime=0;
echo '
分三组计算:
';
$result = getFalseCoin3($coin,0,count($coin)-1);
echo '
';
echo '一共查找了:'.$findTime.'次';
echo '
';
echo '假币位于:'.$result.'处';