1. 程式人生 > >nyoj 737 石子合並(區間DP)

nyoj 737 石子合並(區間DP)

using lac padding gin height space outline style 每次

737-石子合並(一)

內存限制:64MB

時間限制:1000ms

特判: No
通過數:28

提交數:35

難度:3



題目描述:

有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子並成為一堆。合並的過程只能每次將相鄰的兩堆石子堆成一堆,每次合並花費的代價為這兩堆石子的和,經過N-1次合並後成為一堆。求出總的代價最小值。

輸入描述:

有多組測試數據,輸入到文件結束。
每組測試數據第一行有一個整數n,表示有n堆石子。
接下來的一行有n(0< n <200)個數,分別表示這n堆石子的數目,用空格隔開

輸出描述:

輸出總代價的最小值,占單獨的一行

樣例輸入:

3
1 2 3
7
13 7 8 16 21 4 18

樣例輸出:

9
239

題目大意:

給你n堆石子,每堆石子有ai個。你每次可以把兩堆石子合並到一塊,代價為總的石子數。問最少需要多少代價將n堆石子合為一堆。

最基本的區間dp問題。枚舉區間長度,區間,和劃分。

技術分享圖片
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200;
const int inf=1000000000;
int a[maxn+10
]; int sum[maxn+10][maxn+10]; int dp[maxn+10][maxn+10]; int main() { int n; while(scanf("%d",&n)!=EOF) { for(int i=1;i<=n;i++) scanf("%d",a+i); for(int i=2;i<=n;i++) a[i]+=a[i-1]; a[0]=0; for(int i=1;i<=n;i++) for
(int j=i;j<=n;j++) sum[i][j]=a[j]-a[i-1]; memset(dp,0,sizeof(dp)); for(int len=2;len<=n;len++)//直接跳過長度為1的區間,默認為0 { for(int left=1;left<=n;left++) { int right=left+len-1; if(right>n) break; int val=inf; for(int mid=left;mid<right;mid++) val=min(val,dp[left][mid]+dp[mid+1][right]); dp[left][right]=val+sum[left][right]; //printf("%d %d %d\n",left,right,dp[left][right]); } } printf("%d\n",dp[1][n]); } return 0; }
View Code

nyoj 737 石子合並(區間DP)