將n
nn堆石子繞圓形操場排放,現要將石子有序地合併成一堆。規定每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆的石子數記做該次合併的得分。請編寫乙個程式,讀入堆數n
nn及每堆的石子數,並進行如下計算:選擇一種合併石子的方案,使得做n−1
n−1n−
1次合併得分總和最大。選擇一種合併石子的方案,使得做n−1
n−1n−
1次合併得分總和最小。
輸入格式:
第一行包含整數n
nn,表示共有n
nn堆石子。第二行包含n
nn個整數,分別表示每堆石子的數量。
輸出格式:
輸出共兩行:第一行為合併得分總和最小值,第二行為合併得分總和最大值。
資料範圍:
1 ≤n
≤200
1≤n≤200
1≤n≤20
0 思路是動態規劃。由於最後一次合併一定是兩個石堆合併,這兩個石堆中間的」縫隙邊「有n
nn種可能,分別是1∼2
,2∼3
,...
,(n−
1)∼n
,n∼1
1\sim 2,2\sim 3,...,(n-1)\sim n, n\sim 1
1∼2,2∼
3,..
.,(n
−1)∼
n,n∼
1,我們需要列舉全這些可能性。可以用乙個技巧,即將陣列長度增加n−1
n-1n−
1,並且令i
>n,
a[i]
=a[i
−n
]i>n,a[i]=a[i-n]
i>n,
a[i]
=a[i
−n],用這個新的石堆陣列來求合併花費最值,然後列舉所有長度為n
nn的區間,即得答案。其實這就是變相在列舉最後一次合併的縫隙邊。關於非環形石子合併問題,可以參考**如下:
#include
#include
using
namespace std;
const
int n =
410;
int n, a[n]
, s[n]
;int f[n]
[n], g[n]
[n];
intmain()
memset
(f,0x3f
,sizeof f)
;// r1存最小花費,r2存最大花費
int r1 =
0x3f3f3f3f
, r2 =0;
// 列舉區間長度
for(
int l =
1; l <= n; l++
)// 列舉左端點
for(
int i =
1; i + l -
1<
2* n; i++
)// 列舉最後一次合併的分割點,最後一次合併是k及其左的石子與第k + 1及其右的石子的合併
for(
int k = i; k < j; k++
)// 用所有長度為n的區間的花費來更新答案
if(l == n)
} cout << r1 << endl;
cout << r2 << endl;
return0;
}
時間複雜度o(n
3)
o(n^3)
o(n3
),空間o(n
2)
o(n^2)
o(n2)。
1 3 環形佇列
實現 public class circlearrayqueuedemo catch exception e class circlearrayqueue public boolean isfull public boolean isempty public void addqueue int va...
141 環形鍊錶
給定乙個鍊錶,判斷鍊錶中是否有環。高階 你能否不使用額外空間解決此題?乙個快指標走兩步 乙個慢指標走一步 如果相遇就有環 不然沒環 class solution def hascycle self,head type head listnode rtype bool index1 head inde...
1148環形石子合併
時限 1000ms 記憶體限制 10000k 總時限 3000ms 描述在乙個圓形操場的四周擺放著n堆石子 n 100 現要將石子有次序地合併成一堆。規定每次只能選取相鄰的兩堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。編一程式,讀入石子堆數n及每堆的石子數 20 選擇一種合併石子的方...