合并石子

来源:互联网 发布:淘宝秒杀器官方下载 编辑:程序博客网 时间:2024/06/05 11:39

描述
    有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
输入
有多组测试数据,输入到文件结束。
每组测试数据第一行有一个整数n,表示有n堆石子。
接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开
输出
输出总代价的最小值,占单独的一行
样例输入
31 2 3713 7 8 16 21 4 18
样例输出
9239

解题链接(http://www.mamicode.com/info-detail-1488448.html   http://blog.csdn.net/qq_36183935/article/category/6862368)

C语言AC代码:

时间语言内存结果384C400Accepted

#include<stdio.h>#include<string.h>#define INF 2000000005int dp[203][203],sum[203]={0};int DP(int left,int right){int min,mid;if(dp[left][right]>=0)  // 某一个区间左端到右端已经得到最优方案return dp[left][right];if(left==right)         // 说明该区间就一堆石子{return dp[left][right]=0;}for(mid=left;mid<right;mid++){if(dp[left][right]<0)dp[left][right]=INF;// 核心:动态转移方程min=DP(left,mid)+DP(mid+1,right)+(sum[mid]-sum[left-1])+(sum[right]-sum[mid]);if(min<dp[left][right])dp[left][right]=min;}return dp[left][right];}int main(){int n,i,a;while(~scanf("%d",&n))// n表示石子的堆数{for(i=1;i<=n;i++){scanf("%d",&a); // a依次表示第i堆的石子数sum[i]=a+sum[i-1];}memset(dp,-1,sizeof(dp));printf("%d\n",DP(1,n));}return 0;}

借鉴代码:

#include<stdio.h>#define INF 2000000005int dp[205][203],sum[203];int min(int a,int b){return a>b?b:a;}int main(){int n,a;while(~scanf("%d",&n)){for(int i=1;i<=n;i++){scanf("%d",&a);sum[i]=sum[i-1]+a;dp[i][i]=0;}// 区间DPfor(int count=2;count<=n;count++){   // 遍历合并count=2堆、3堆、...n堆的情况for(int start=1;start<=n-count+1;start++){   // start表示每个区间的始点int end=start+count-1;  // end表示对应的该区间的终点dp[start][end]=INF;for(int mid=start;mid<=end;mid++){dp[start][end]=min(dp[start][end],dp[start][mid]+dp[mid+1][end]+sum[end]-sum[start-1]);}}}printf("%d\n",dp[1][n]);}return 0;}