1. 程式人生 > >【tyvj】【區間dp】石子合併

【tyvj】【區間dp】石子合併

【問題描述】

在一個操場上擺放著一行共n堆的石子。現要將石子有序地合併成一堆。規定每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆石子數記為該次合併的得分。請編輯計算出將n堆石子合併成一堆的最小得分和將n堆石子合併成一堆的最大得分。

【輸入檔案】

輸入第一行為n(n<1000),表示有n堆石子,第二行為n個用空格隔開的整數,依次表示這n堆石子的石子數量(<=1000)

【輸出檔案】

輸出將n堆石子合併成一堆的最小得分和將n堆石子合併成一堆的最大得分。

【輸入樣例】

3
1 2 3

【輸出樣例】

9 11

【分析思路】

對於區間[i,j],列舉以k(k=i~j-1)為分界線求[i,k]與[k+1,j]的最大價值和的最大值。
當i==j時,不需要合併故價值為val[i];

【程式碼實現】

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define INF 0xfffffff
#define REP(a,b) for(int i=a;i<=b;i++)
#define RES(a,b) memset(a,b,sizeof(a))
using namespace std;

int n,w[120],dp[120][120],pre[120];

int solve(int l,int r){
    if(dp[l][r]!=-1
) return dp[l][r]; if(l==r) return dp[l][r]=0; int sum=pre[r]-pre[l-1],ans=10000000; REP(l,r-1){ ans=min(ans,solve(l,i)+solve(i+1,r)); } //printf("dp[%d][%d]=%d\n",l,r,ans+sum); return dp[l][r]=ans+sum; } int main(){ RES(dp,-1); pre[0]=0; scanf("%d",&n); REP(1,n) { scanf
("%d",&w[i]); pre[i]=pre[i-1]+w[i]; } printf("%d",solve(1,n)); return 0; }