nyoj 737 石子合並(區間DP)
阿新 • • 發佈:2018-10-05
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+10View Code]; 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; }
nyoj 737 石子合並(區間DP)