在乙個圓形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。
試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.
輸入格式:
資料的第1行試正整數n,1≤n≤100,表示有n堆石子.第2行有n個數,分別表示每堆石子的個數.
輸出格式:
輸出共2行,第1行為最小得分,第2行為最大得分.
輸入樣例#1:
44 5 9 4
輸出樣例#1:
4354
區間dp啦!
首先斷環為鏈,把整個陣列複製一遍。所以第乙個要注意的就是陣列大小。(必須都是兩倍的maxn,否則你就得到了fast runtime error transform的技能!)(我還re了兩次,貌似是題目的資料範圍有更改但題面沒有說明。)(你的好友ac率已下線)
然後開始dp亂搞寫狀態轉移方程。區間dp的常規狀態:dp[i][j]表示合併第i到第j個石子的最大/最小分數。狀態轉移方程就是:
dp[i][j] = min/max(dp[i][j], dp[i][k]+dp[i][k+1]+s[j]-s[i-1]);
(其中s是字首和)
這個方程不難理解,其實就是i到k堆石子合併的分數加上k+1到j堆石子合併的分數再加上當前合併的分數(i到j的石子個數之和)。
但是不能像我一樣愚蠢!
我一開始把轉移方程寫成了
dp[i][j] = min/max(dp[i+1][j]+s[j]-s[i-1], dp[i][j-1]+s[j][i-1]);
居然沒想到合併一堆石子可以是由兩堆已經進行過合併的石子產生的。(愚蠢!)
1 #include 2using
namespace
std;
3const
int maxn = 500 + 10;4
int n, stone[2*maxn], mi[2*maxn][2*maxn], mx[2*maxn][2*maxn], s[2*maxn];
5int
main()622
}23}24
int ans1 = 0x3f3f3f3f, ans2 = 0;25
for (int i = 1; i <= n; i++)
26 ans1 = min(ans1, mi[i][i+n-1]), ans2 = max(ans2,mx[i][i+n-1
]);27 cout << ans1 << endl << ans2 <28return0;
29 }
石子合併NOI1995 區間DP
題目 在乙個操場上一排地擺放著n堆石子。現要將石子有次序的合併成一堆。規定每次只選相鄰的2堆石子合成新的一堆,並將新的一堆石子數記為該次合併的得分。程式設計任務 設計乙個程式,計算出將n堆石子合併成一堆的最小得分。1 n 100,0 ai 200。擴充套件題目 環形結構上的動態規劃問題 在乙個圓形操...
區間dp板子題 noi1995 石子合併
非常經典的區間dp模板 對於每乙個大於二的區間 我們顯然都可以將它拆分成兩個子串行 那麼分別計算對於每個取最優值即可 pragma gcc optimize o2 include include include include include include include include incl...
NOI1995 石子合併
在乙個園形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.圓的話就用2 n 1,即只有n種情況 include using namespace ...