10個小球用天平找出重量不同的那個


上周被人出了一道算法題目,題目的內容是:有10個小球,外觀一樣,其中1個小球和其他9個小球重量不一樣,請使用天平以最少的次數找出這個重量不一樣的小球。

解題思路:其實這是一個很典型使用分治算法的例子,由於不知道這個特別的小球是比其他球重還是輕,所以我們不能簡單的使用二分法去求解,所以我選擇3為模。

解題步驟:

1、將10個球分成4個數組,分別是A[a1, a2, a3],B[b1, b2, b3], C[c1, c2, c3], D[d1];假設這個重量不一樣的球為n,其他普通球的任意一個是m;

2、首先拿A和B、A和C稱,如果A==B && A== C,那么直接得到結果n = d1;否則我們可以獲得兩個結果,第一個n in [A|B|C],第二個是n比m重還是輕。

說明:

  如果A > B && A > C, 那么n in A,n > m

  如果A > B && A == C,那么n in B,n < m

  如果A > B && A < C, 這種情況不存在

  如果A == B && A > C,那么n in C, n < m

  如果A == B && A == C,這種情況我們已經得到結果

  如果A == B && A < C,那么n in C, n > m

  如果A < B && A < C, 那么n in A,n < m

  如果A < B && A == C, 那么n in B,n > m

  如果A < B && A > C,這種情況不存在 

3、我們得到n in [A|B|C]后,取A、B、C中的前兩個球稱,因為已經知道n比m重還是輕,所以稱完后可以直接得到n。假設n in A

說明:

  如果a1 > a2 && n > m, 那么n = a1

  如果a1 > a2 && n < m, 那么n = a2

  如果a1 == a2 ,那么n = a3

  如果a1 < a2 && n > m,那么n = a2

  如果a1 < a2 && n < m,那么n = a1

 

上代碼:

<?php

$data = array(0, 0, 0, 0, 1, 0, 0, 0, 0, 0);

class filterBall {
    public $theSpecial; //特殊球 1 = 重, -1 = 輕
    public $balanceTimes = 0;
    /*
     * param integer & array $left 左邊的球
     * param integer & array $right 右邊的球
     * return 左邊的球重=-1 相同重=0 右邊球重=1
     */
    public function balance($left, $right) {
        $this->balanceTimes++;
        if (is_array($left)) {
            $left = array_sum($left);
        }
        if (is_array($right)) {
            $right = array_sum($right);
        }
        if ($left == $right) {
            return 0;
        } elseif ($left > $right) {
            return -1;
        } else {
            return 1;
        }
    }

    function execute($data) {
        $mod = intval(count($data) / 3); //取模
        // 將數組切分成3 - 4個每個有$mod個元素的數組
        $i = 0;
        $j = 0;
        $newArray = array();
        while($i < count($data)) {
            if (isset($newArray[$j]) && count($newArray[$j]) >= $mod) {
                $j++;
            }
            $newArray[$j][] = $data[$i];
            $i++;
        }

        $return0 = $this->balance($newArray[0], $newArray[1]);
        $return1 = $this->balance($newArray[0], $newArray[2]);
        switch((string)$return0.(string)$return1) {
            case '11':
                $this->theSpecial = -1;
                return 0 + $this->compareThird($newArray[0]);
            case '10':
                $this->theSpecial = 1;
                return 3 + $this->compareThird($newArray[1]);
            case '01':
                $this->theSpecial = 1;
                return 6 + $this->compareThird($newArray[2]);
            case '00':
                return 9;
            case '0-1':
                $this->theSpecial = -1;
                return 6 + $this->compareThird($newArray[2]);
            case '-10':
                $this->theSpecial = -1;
                return 3 + $this->compareThird($newArray[1]);
            case '-1-1':
                $this->theSpecial = 1;
                return 0 + $this->compareThird($newArray[0]);
        }
    }

    /*
     * 通過前兩次的比對,知道特別球是重還是輕,然后在三個球中比對一次,知道三個球中特殊球的索引
     */
    public function compareThird($childArray) {
        $return = $this->balance($childArray[0], $childArray[1]);
        switch($return) {
            case 1:
            case -1:
                if ($return == $this->theSpecial) {
                    return 1;
                } else {
                    return 0;
                }
                break;
            case 0:
                return 2;
                break;
        }
    }
}

echo '<pre>';
print_r($data);
$filter = new filterBall();
echo sprintf('鍵值:%s, 比對了%s次', $filter->execute($data), $filter->balanceTimes);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM