問題:
假設要把長度爲n釐米的木棒切分爲1釐米長的小段,但是1根木棒只能由1人切分,當木棒被切分爲3段後,可以同時由3個人分別切分木棒。求最多有m個人時,最少要切分幾次。
譬如n=8,m=3時如下圖所示,切分4次就可以了。
求當n=20,m=3時的最少切分次數。
求當n=100,m=5時的最少切分次數。
思路:
這道題最難的不是算法,而是理解題意。
木棒剛開始只有1根,題目規定“1根木棒只能由1人切分”,此時由1人切分後,變成2根;
2根木棒再做切分,也要滿足“1根木棒只能由1人切分”的規則,所以此時由2個人,每人切1根,變成了4根;
隨後,題目說“當木棒被切分爲3段後,可以同時由3個人分別切分木棒”,也就是說,
當木棒根數達到上限人數後,每一次便只能切分出上限人數的根數了。
而在這之前,每次都有足夠的人切木棒,每次也都是一分爲二,木棒的數量都是翻倍遞增
用文字來描述便是:
當前木棒數量 >= 人數上限時,新木棒數量 = 原有木棒數量 + 上限人數;
當前木棒數量 < 人數上限時,新木棒數量 = 原有木棒數量 * 2;
當新木棒數量大於等於木棒長度時,切分結束。
此題可以用遞歸和循環兩種方法來解。
遞歸:
遞歸的結束條件便是current(當前的木棒數)>= n (木棒長度)。
當current (當前的木棒數)< m(人數上限)時,current = current * 2。
當current(當前的木棒數)>= m (人數上限)時,current = current + m;
每次遞歸時,就將當前木棒數通過參數傳入下一次遞歸中,直至滿足退出條件。
循環:
循環的結束條件與遞歸一樣,也是當current(當前的木棒數)>= n (木棒長度)時退出,即是current < n時一直執行循環。
當current (當前的木棒數)< m(人數上限)時,current = current + current。
當current(當前的木棒數)>= m (人數上限)時,current = current + m;
每執行一次循環,count(循環計數,即切分次數)加1。
解答:
php
// 遞歸
// m 爲上限人數
// n 爲木棒長度
// current 爲當前木棒數量
function cutBar($m, $n, $current)
{
if ($current >= $n) {
return 0;
} elseif ($current < $m) {
return 1 + cutBar($m, $n, $current * 2);
} else {
return 1 + cutBar($m, $n, $current + $m);
}
}
// 循環
function cutBar2($m, $n)
{
$current = 1;// 初始木棒數
$count = 0; // 切分計數
while ($current < $n) {
$current += $current < $m ? $current : $m;
$count++;
}
return $count;
}
$rs = cutBar(3, 8, 1);
echo $rs."\n";
$rs = cutBar(3, 20, 1);
echo $rs."\n";
$rs = cutBar(5, 100, 1);
echo $rs."\n";
$rs = cutBar2(3, 8);
echo $rs."\n";
$rs = cutBar2(3, 20);
echo $rs."\n";
$rs = cutBar2(5, 100);
echo $rs."\n";
輸出:
4
8
22
4
8
22
golang
package main
import "fmt"
func main() {
rs := cutBar(3, 8, 1)
fmt.Println(rs)
rs = cutBar(3, 20, 1)
fmt.Println(rs)
rs = cutBar(5, 100, 1)
fmt.Println(rs)
rs = cutBar2(3, 8)
fmt.Println(rs)
rs = cutBar2(3, 20)
fmt.Println(rs)
rs = cutBar2(5, 100)
fmt.Println(rs)
}
func cutBar(m, n, current int) int {
if current >= n {
return 0
} else if current < m {
return 1 + cutBar(m, n, current*2)
} else {
return 1 + cutBar(m, n, current+m)
}
}
func cutBar2(m, n int) int {
current := 1
count := 0
for current < n {
if current < m {
current += current
} else {
current += m
}
count++
}
return count
}
輸出:
4
8
22
4
8
22