題目描述 description
有n堆石子排成一列,每堆石子有乙個重量w[i], 每次合併可以合併相鄰的兩堆石子,一次合併的代價為兩堆石子的重量和w[i]+w[i+1]。問安排怎樣的合併順序,能夠使得總合併代價達到最小。
輸入描述 input description
第一行乙個整數n(n<=100)
第二行n個整數w1,w2...wn (wi <= 100)
輸出描述 output description
乙個整數表示最小合併代價
樣例輸入 sample input
4 1 1 4
樣例輸出 sample output
芒果君:這是我部落格的第一道題啊~是一道dp啊~其實剛看到的時候有點懵,然後又看了一本通上的**,果然,我並沒有恍然大悟otz 用f[i][j]表示從第i個到第j個的最小合併代價,狀態轉移方程是,f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]),就是判斷原來的方案和你列舉的新的兩端合併起來哪個更小。然後這道題也告訴我memset新的用法……
#include#includeusing
namespace
std;
int f[101][101],s[101
],n,i,j,k,x;
int min(int a,int
b)int
main()
memset(f,
127/3,sizeof
(f));//把每一位都賦予乙個很大的整數
for(i=1;i<=n;++i)
for(i=n-1;i>=1;--i)//合併2個、合併3個……合併n個}}
printf("%d
",f[1
][n]);
return0;
}
然後這道題還有乙個公升級版,就是洛谷的1880,只不過把這個鏈狀的變成了環狀的,最大值和最小值都要求,我就稍微改了一下,比如第一次做「1 2 3 4 5」,第二次做「2 3 4 5 1」,第五次做「5 1 2 3 4」,這樣就解決問題了。
#include#includeusing
namespace
std;
int f1[110][110],f2[110][110],a[101],s[101],n,i,j,k,t,x,min=1
<<30
,max;
int min(int a,int
b)int max(int a,int
b)int
main()
for(t=1;t<=n;++t)
for(i=t;i<=n;++i)
memset(f1,
127/3,sizeof
(f1));
memset(f2,
0,sizeof
(f2));
for(i=1;i<=n;++i)
for(i=n-1;i>=1;--i)}}
min=min(f1[1
][n],min);
max=max(f2[1
][n],max);
}printf(
"%d\n%d\n
",min,max);
return0;
}
Code Vs 1048 石子歸併
石子合併 給出n顆石子,把相鄰的石子合併在一起,最後變成一堆的最小費用。很明顯,石子最後都會變成一堆,即區間 i,j 由 i,k k 1.j 區間大的由區間小的而來,所以區間長度為階段,我們需要列舉起點和結束點。動態轉移方程 令f i j 表示以i為起點,j為結束點的最小費用,得 f i j min...
code VS 1048 石子歸併
題目描述 description 有n堆石子排成一列,每堆石子有乙個重量w i 每次合併可以合併相鄰的兩堆石子,一次合併的代價為兩堆石子的重量和w i w i 1 問安排怎樣的合併順序,能夠使得總合併代價達到最小。輸入描述 input description 第一行乙個整數n n 100 第二行n個...
Codevs1048 石子歸併
題目描述 description 有n堆石子排成一列,每堆石子有乙個重量w i 每次合併可以合併相鄰的兩堆石子,一次合併的代價為兩堆石子的重量和w i w i 1 問安排怎樣的合併順序,能夠使得總合併代價達到最小。輸入描述 input description 第一行乙個整數n n 100 第二行n個...