傳送
這是乙個年代久遠的區間dp (好像以前培訓的時候講了,但是現在才想起來去a)
區間dp常用狀態:
f[i][j]:以i為左端點,j為右端點的最優解
第一層迴圈列舉區間長度,第二層迴圈列舉起點,第三層列舉中間的斷點
(貌似寫到這裡這個題就寫完了)
特點:問題能轉換為兩兩合併的問題(such as 能量項鍊,石子合併),當然可以再bt一點弄分解問題
步入正題
我們設f[i][j]為合併i到j的最大得分,g[i][j]為最小得分(**裡會出現一些奇怪的東西)。要合併i到j,則對於i,j之間的乙個k來說,肯定是先合併了i到k,再合併k+1到 j。
而且合併完了還要計算合併i到k與合併k+1到j的得分。得分就是s[i](第i堆石子的個數)+s[i+1]+........+s[j],為了節省時間,我們用字首和的形式計算,即sum[i]=s[1]+s[2]+...+s[i],那麼得分也就是sum[j]-sum[i-1].
綜上,f[i][j]=max(f[i][k],f[k+1][j])+sum[j]-sum[i-1](i<=kg[i][j]=min(g[i][k],g[k+1][j])+sum[j]-sum[i-1](i<=k我們再來考慮邊界狀態
f[i][i]=0,g[i][i]=0,因為合併i到i相當於沒有合併,不得分
g[i][j]=inf,(取min用),f[i][j]=0(取max用)
這個題還牽扯到環,so這時候就該扯扯環變鏈了
因為n與1相鄰,所以我們不妨把s[n+1]設成與s[1]一樣,這樣就可以處理合併n和1了。
但是合併n到2,3,4...n-1呢?(注意不是2,3,4...n-1到n)
思考過後,我們發現可以使s[n+i]=s[i],這樣就可以處理起點是n的情況了
這樣就可以寫**了(迴圈順序在開頭)
(奇怪的變數名警告)
#include#include另一道區間dp典型題:能量項鍊#include
#include
#include
using
namespace
std;
int n,s[209],mitsu[209][209],nobu[209][209],sum[209];//
nobu是最大值,mitsu是最小值
int read()//
一堆快讀
while(ch>='
0'&&ch<='9'
)
if(flag)x=-x;
returnx;}
intmain()
for(int i=1;i<=2*n;i++)
for(int len=1;len<=n;len++)
nobu[st][end]+=sum[end]-sum[st-1
]; mitsu[st][end]+=sum[end]-sum[st-1
]; }
}int maxn=-1,minn=214748364
;
for(int i=1;i<=n;i++)//
統計答案
printf(
"%d\n%d
",minn,maxn);}//
i love akchi mitsuhide and oda nobu naga
p1880 石子合併
先從線性的開始吧。有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n 1次合併後成為一堆。求出總的代價最小值。樣例 輸入 3 1 2 3 7 13 7 8 16 21 4 18 輸出 9 239 ...
P1880 石子合併
石子歸併最簡單的情況是一排石子,典型的區間dp問題。dp i j 的含義是區間 i,j 合併之後的最大或最小花費 轉移方程 dp i j max min dp i j dp i k dp k 1 j val i,j 對於區間 i,j 它可以由區間 i,k 和區間 k 1,j 合併而來,合併時,要加上...
洛谷P1880 石子合併
描述 在乙個園形操場的四周擺放n堆石子,現要將石子有次序地合併成一堆.規定每次只能選相鄰的2堆合併成新的一堆,並將新的一堆的石子數,記為該次合併的得分。試設計出1個演算法,計算出將n堆石子合併成1堆的最小得分和最大得分.輸入格式 資料的第1行試正整數n,1 n 100,表示有n堆石子.第2行有n個數...