【題目描述】
小 $m$ 培養了 $n$ 個菌落。其中每個菌落有質量和顏色兩種屬性,顏色只可能為紫色或紅色。小 $m$ 想把所有的菌落合併成乙個菌落。因為合併的過程非常費勁,小 $m$ 每天只能進行一次合併,整個過程需要進行 $n − 1$ 天。一次合併會將兩個菌落變成乙個菌落。如果原來兩個菌落的顏色相同,兩個菌落會進行融合,新的菌落質量為原來兩個菌落質量之和,顏色不變;如果原來兩個菌落的顏色不同,兩個菌落會進行戰鬥,新的菌落質量為原來兩個菌落質量之差,顏色為質量較大的那個菌落。需要特殊說明的是,中間過程中如果產生了質量為 $0$ 的菌落,這個菌落也需要參與後續合併而不能直接捨棄;可以證明將質量為 $0$ 的菌落視為紫色或紅色都不影響後續的計算。
每天的合併結束後,小 $m$ 都需要餵養當前的每個菌落。對於乙個質量為 $w$ 的菌落,小 m 需要花費 $w^2$ 單位的能量對它進行一天的餵養。
小 $m$ 希望你幫他求出菌落的最佳合併順序,使得餵養所消耗的總能量最少。你只需要輸出所需要的最小能量即可。
【輸入格式】
從檔案 germ.in 中讀入資料。
輸入的第一行包含乙個正整數 $t$,表示資料的組數。對於所有的測試點,保證$ t = 10$。
對於每組資料,第一行包含乙個正整數 $n$,表示最初菌落的個數。
接下來 $n$ 行,每行包含乙個正整數和乙個字串,表示這個菌落的質量和顏色。若字串為 $743481$,表示這個菌落是紫色;若字串為 $8b0012$,表示這個菌落是紅色。保證不會出現其他的字串,保證給出的正整數不超過 $10^6$ 。
【輸出格式】
輸出到檔案 germ.out 中。
對於每組資料,輸出一行乙個整數,表示消耗的最少總能量。注意這個值可能很大,請注意選用合適的資料型別來儲存它。
【樣例輸入】104
3 743481
20 743481
7 8b0012
18 743481
310 8b0012
13 743481
13 8b0012
514 743481
16 8b0012
2 8b0012
9 8b0012
8 8b0012
411 8b0012
15 8b0012
4 8b0012
8 8b0012
211 8b0012
6 8b0012
48 8b0012
16 8b0012
16 8b0012
3 8b0012
220 743481
17 743481
36 8b0012
20 743481
13 8b0012
419 8b0012
15 743481
4 8b0012
1 743481
211 8b0012
14 8b0012
【樣例輸出】
2238
200980
2688
2893467
1369
86107
625【樣例解釋】
對於樣例中的第一組資料,最優的合併方案如下:
1. 合併紫色的 $20$ 和紅色的 $7$,得到紫色的 $13$;餵養的能量花費為 $3^2 +13^2 +18^2 = 502$。
2. 合併紫色的 $13$ 和紫色的 $3$,得到紫色的 $16$;餵養的能量花費為 $16^2 +18^2 = 580$。
3. 合併紫色的 $16$ 和紫色的 $18$,得到紫色的 $34¥;餵養的能量花費為 ¥34^2 = 1156$。
可以證明沒有更優的方案。
【子任務】
$n<=10$。
對於全是同一種顏色的情況,不能從小到大兩兩合併,這樣得出來的解並不是最優的,同色的1~10就是個反例。
可以當做乙個模擬退火題:
模擬退火題的典例——哈密頓迴路題有個較優演算法:將初始退火序列設為圖的最小生成樹的遍歷。
也可以當做乙個貪心暴力折中題:
把這題的暴力和貪心對比一下(當然貪心的結果會大一點點),會發現貪心出現的少量錯誤答案只比暴力的正確答案多一點點,然後輸出一下路徑,發現貪心的路徑與暴力的路徑很相似。因此把每一步的$n^2$列舉的所有情況所導致的結果從小到大排序,然後跑前幾種即可(mangod跑了5個就a了)。
std:
f(i,s)表示合併i次後時,經過的點的集合是s。
這個集合s怎麼表示?
我們都知道,s是把集合壓成乙個數,代表一種情況。
然而這裡並不能只存個表示01二進位制序列的數,表示乙個數選或不選,因為乙個數在被合併入不同的菌落時,是有不同的後效性的(後效性就是說前面的決策對後面所有答案都有影響),因此有多種不同的合併情況需要被統計。
也就是說,我們需要記錄每個數被合併到了哪個菌落裡。這就需要並查集的思想了。
我們讓每個初始菌落存乙個數,表示這個菌落被合併若干次後,該菌落中編號最小的初始菌落的編號。那麼存的這個數相同的初始菌落就都已經被合併到乙個菌落裡了。
容易發現,每個初始菌落存的數都不會超過自己的編號。
那麼$n$個初始菌落的編號總種數就是$n!$,一看$n=10$,總種數大約$100w$。這就可以狀態壓縮了。
轉移方程:
複雜度:$o(n!
計算思維綜合訓練 D 2018102
個人新增了注釋,答案由學校課程組給出,不是原創回答 include using namespace std int daynum 13 bool checkyear int x 判斷給出的年份x是否為閏年 void nxt int a,int b,int c 移動到下乙個日期 if b 12 if ...
單鏈表的合併(交叉合併,公升序合併)
單鏈表的合併情況有如下幾種 1 length l1 length l2 2 length l1 length l2 3 length l1 交叉合併的重點在交叉,不保證合併後的資料是有序的 公升序單鏈表合併的重點在公升序,可以保證合併後的資料是公升序的,但是前提是輸入的鍊錶是公升序的 include...
Pandas合併之Concat合併
pd.concat objs,axis 0,join outer join axes none,ignore index false,keys none,levels none,names none,verify integrity false objs series或者dataframe物件構成的...