一、問題引入
農夫約翰為了修理柵欄,要將一塊很長的木塊切成n塊。準備切成的長度分別是l1、l2、、、,ln,未切割前的木板長度切好為切割後木板長度的總和。每次切斷木板時的開銷是這塊木板的長度。(1 ≤ n ≤ 20000,0 ≤ li ≤ 50000)
二、解題思路
由於n的值非常大,不可能列舉所有情況再求解,必須用一種比較高效的演算法。木板的切割循序不確定,看似自由度很高,是先選擇切出較短的,還是切較長的。如果我們把一種完全切割後的情況列舉出來,會發現可以用貪心演算法
驚奇的發現,這種切法的切割費用之和 == 所有非葉子節點權值和 == 葉子節點的權值 * 深度(根節點深度為0)
即 33 = 15 + 7 + 8 + 3 = 3*2 + 4*2 + 5*2 + 1*3 + 2*3
問題轉化為,已知所有的葉子節點和根節點,求葉子節點的權值 * 深度和的最小值。
顯然,使權值大的深度小,權值小的深度大。於是,此時的最佳切割方法應該具有如下性質:
最短版和次短板應該是兄弟節點
這一性質在切割過程中始終成立,反過來,我們可以根據這種性質建立起對應的二叉樹。即每次合併最小的,合併後的值加到總費用中。(注意建立的樹不唯一,但每種的結果一樣,所以選其中一種就行)
由於是每次取最小和次小合併,維護乙個優先佇列就行
三、**實現
1 #include2 #include3 #include4四、總結using
namespace
std;
56 typedef long
long
ll;7
const
int maxn = 20000 + 10;8
intn, l[maxn];910
void
slove()
1130 printf("
%lld\n
", ans);31}
3233
intmain()
3441
return0;
42 }
NOIP模擬 切割木板
小 z 是個特別墮落的小朋友,上數學課的時候經常有奇奇怪怪的想法。小 z 的的包裡有塊 n m 的長方形木板,小 z 想把木板全部切成 1 1 的小正方形 用來玩拼圖 但木板本身並不均勻,因此從不同的線切割下去要花不同的代價。而且對於一塊木板,切割一次以後就被分割成兩塊,而且由於不能把這兩塊木板拼在...
NOIP模擬 切木板(貪心)
有乙個 m n 的矩形木板。你需要把這個木板切成 1 1 的小方塊,也就是豎著切 n 1 刀 橫著切 m 1 刀。橫著切第 i 個位置的權值為 xi 豎著切第 j 個位置的權值為 yj 切某一刀時的費用為切這一刀的權值乘上切過的塊數。請你安排切的順序使得所有費用之和最小。第一行兩個數 m,n 接下來...
NOIP模擬 切木板(貪心)
有乙個 m n 的矩形木板。你需要把這個木板切成 1 1 的小方塊,也就是豎著切 n 1 刀 橫著切 m 1 刀。橫著切第 i 個位置的權值為 xi 豎著切第 j 個位置的權值為 yj 切某一刀時的費用為切這一刀的權值乘上切過的塊數。請你安排切的順序使得所有費用之和最小。第一行兩個數 m,n 接下來...