1. 程式人生 > >石子歸併問題(codevs 1048)

石子歸併問題(codevs 1048)

題目描述 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

4 1 1 4
樣例輸出 Sample Output
18

動規經典問題(然而我並不會動規QAQ)

由於每次合併只能合併兩個相鄰的石堆,並不能像合併果子一樣隨意選取,因此貪心策略(先把小的合併光) 是不可取的
這樣的話,處理每一處石堆向後len長度為止合併的最小代價即可
dp[i][j]為從i到j的最小合併代價
因為每一次的處理都是區域性的最優解
因此不斷更新的過程中得到dp[1][n]的最優解即是最後答案(這是我理解的動規把QAQ)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int xl[12450],dp[450][450];
int sum[450
][450]; int main() { int n; cin>>n; for(int i=1;i<=n;i++){ scanf("%d",&xl[i]); } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ for(int k=i;k<=j;k++){ sum[i][j]+=xl[k]; } } } for(int len=2;len<=n;len++){
for(int i=1;i<=n-len+1;i++){ int t=i+len-1; dp[i][t]=214748364; for(int k=i;k<=t;k++){ if(dp[i][t]>dp[i][k]+dp[k+1][t]+sum[i][t]){ dp[i][t]=dp[i][k]+dp[k+1][t]+sum[i][t]; } } } } cout<<dp[1][n]<<endl; return 0; }