題目描述
description
在乙個操場上擺放著一排n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。
試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分。
輸入描述
input description
第一行是乙個數n。
以下n行每行乙個數a,表示石子數目。
輸出描述
output description
共乙個數,即n堆石子合併成一堆的最小得分。
樣例輸入
sample input
樣例輸出
sample output
資料範圍及提示
data size & hint
對於 30% 的資料,1≤n≤100
對於 60% 的資料,1≤n≤1000
對於 100% 的資料,1≤n≤40000
對於 100% 的資料,1≤a≤200
思路:1. 這類題目一開始想到是dp, 設dp[i][j]表示第i堆石子到第j堆石子合併最小得分.
狀態方程: dp[i][j] = min(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
sum[i]表示第1到第i堆石子總和. 遞迴記憶化搜尋即可.
2. 不過此題有些不一樣, 1<=n<=50000範圍特大, dp[50000][50000]開不到這麼大陣列.
問題分析:
(1). 假設我們只對3堆石子a,b,c進行比較, 先合併哪2堆, 使得得分最小.
score1 = (a+b) + ( (a+b)+c )
score2 = (b+c) + ( (b+c)+a )
再次加上score1 <= score2, 化簡得: a <= c, 可以得出只要a和c的關係確定,
合併的順序也確定.
(2). garsiawachs演算法, 就是基於(1)的結論實現.找出序列中滿足stone[i-1] <=
stone[i+1]最小的i, 合併temp = stone[i]+stone[i-1], 接著往前面找是否
有滿足stone[j] > temp, 把temp值插入stone[j]的後面(陣列的右邊). 迴圈
這個過程一直到只剩下一堆石子結束.
(3). 為什麼要將temp插入stone[j]的後面, 可以理解為(1)的情況
從stone[j+1]到stone[i-2]看成乙個整體 stone[mid],現在stone[j],
stone[mid], temp(stone[i-1]+stone[i-1]), 情況因為temp < stone[j],
因此不管怎樣都是stone[mid]和temp先合併, 所以講temp值插入stone[j]
的後面是不影響結果.
1 #include2 #include3view code#define ll long long
4#define maxn 50010
5using
namespace
std;
6int t=1
,n,a[maxn];
7 ll ans=0
;8 inline void read(int&x)
13 inline void go(int
k) 27}28
intmain()
35while(t>1) go(t-1
);36 printf("
%lld\n
",ans);
37return0;
38 }
2298 石子合併
2008年省隊選拔賽山東 時間限制 1 s 空間限制 256000 kb 題目等級 gold 在乙個操場上擺放著一排n堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的得分。試設計乙個演算法,計算出將n堆石子合併成一堆的最小得分。輸入描...
SDOI2008 石子合併 題解
題面 garsiawachs演算法專門解決石子合併問題 設乙個序列是a 0.n 1 每次尋找最小的乙個滿足a k 1 a k 1 的k,那麼我們就把a k 與a k 1 合併,並向前尋找乙個第乙個超過他們的和的數,把這個數插入到他後面 include define inc i,a,b for reg...
282 石子合併
設有n堆石子排成一排,其編號為1,2,3,n。每堆石子有一定的質量,可以用乙個整數來描述,現在要將這n堆石子合併成為一堆。每次只能合併相鄰的兩堆,合併的代價為這兩堆石子的質量之和,合併後與這兩堆石子相鄰的石子將和新堆相鄰,合併時由於選擇的順序不同,合併的總代價也不相同。例如有4堆石子分別為 1 3 ...