在乙個圓形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。
試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.
資料的第1行試正整數n,1≤n≤100,表示有n堆石子.第2行有n個數,分別表示每堆石子的個數.
輸出共2行,第1行為最小得分,第2行為最大得分.
由於本人是大蒟蒻,所以這道題做了好幾個月(其實第一眼看就想到斷環成鏈,但是蒟蒻是完美主義者,所以鐵了心要寫dp)
斷環成鏈的就不說了,點開luogu 題解一大堆.
這裡說一下我的dp思路:
若果是一條鏈,那麼這個問題是很好處理的,有狀態轉移方程(以最小值為例) : f[i][j]=min | i<=k<=j.
那麼成環之後也可以用類似的狀態: 假設石子的序號逆時針遞增,則f[i][j] 表示以逆時針方向的最優合併,那麼f[i][j]|0<=i<=n-1,0<=j<=n-1 就足以表示所有的情況(lrj:想一想,為什麼 ='-') )
蒟蒻覺得用記憶化搜尋比用遞推好(其實是因為遞推的話蒟蒻不知道順序),那麼,請看**:
1//2stoneunion3 #include4 #include5
const
int n=100+1,inf=2e9+1;6
inta[n],sum[n],mins[n][n],maxs[n][n],n;
7bool
calmin[n][n],calmax[n][n];
8int min(int a,int b)
9int max(int a,int b)
10 inline int sum(int,int
);11 inline int dp(int,int,int val[n][n],bool vis[n],int(*)(int,int
));12 inline void
init();
13 inline void
dp();
14 inline void
printanswer();
15int
main()
1622 inline int sum(int l,int
r)23
28 inline void
init()
2937
}38 inline void
dp()
39 46}
47 inline int dp(int
from,int to,int val[n],bool vis[n],int (*f)(int,int
))48
60return val[from][to]=ans;61}
62else
if(from==to)
63else
6471
return val[from][to]=ans;72}
73}74 inline void
printanswer()
7582 printf("
%d\n%d
",mina,maxa);
83 }
洛谷1880 石子合併
在乙個園形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.輸入格式 資料的第1行試正整數n,1 n 100,表示有n堆石子.第2行有n個數,分別...
洛谷1880 石子合併
在乙個園形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.輸入格式 資料的第1行試正整數n,1 n 100,表示有n堆石子.第2行有n個數,分別...
洛谷P1880 石子合併
描述 在乙個園形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.輸入格式 資料的第1行試正整數n,1 n 100,表示有n堆石子.第2行有n個數...