Description
在操场上沿一直线排列着
n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆石子合并成新的一堆,
并将新的一堆石子数记为该次合并的得分。允许在第一次合并前对调一次相邻两堆石子的次序。
计算在上述条件下将n堆石子合并成一堆的最小得分。
Input
输入数据共有二行,其中,第1行是石子堆数n≤100;
第2行是顺序排列的各堆石子数(≤20),每两个数之间用空格分隔。
Output
输出合并的最小得分。
Sample Input
3 2 5 1
Sample Output
11 第一道区间dp,这题设一个数组dp[i][j]表示从i取到j的最小得分。 状态转移方程:dp[i][i+len]=min(dp[i][i+len],dp[i][i+len1]+dp[i+len1+1][i+len]+sum[i+len]-sum[i-1]);这里注意所有的dp[i][i]为0,因为只有一个数的时候不用合并,所以是0。因为题目允许第一次开始取的时候相邻数字能搞交换,所以外面加个循环,同时每次的sum[],dp[i][i+1]都要重新初始化。另外,这题用四边形优化会大大加快速度。#include<stdio.h> #include<string.h> #define inf 88888888 int min(int a,int b){ return a<b?a:b; } int a[106],dp[106][106],sum[106]; int main() { int n,m,i,j,temp,len,sum1,ans,len1,k; while(scanf("%d",&n)!=EOF) { for(i=1;i<=n;i++){ scanf("%d",&a[i]); } sum1=inf; for(k=1;k<=n-1;k++){ temp=a[k]; a[k]=a[k+1]; a[k+1]=temp; memset(sum,0,sizeof(sum)); memset(dp,inf,sizeof(dp)); for(i=1;i<=n-1;i++){ sum[i]=sum[i-1]+a[i]; dp[i][i+1]=a[i]+a[i+1];dp[i][i]=0; } dp[n][n]=0;sum[n]=sum[n-1]+a[n]; for(len=2;len<=n-1;len++){ for(i=1;i+len<=n;i++){ for(len1=0;len1<len;len1++){ dp[i][i+len]=min(dp[i][i+len],dp[i][i+len1]+dp[i+len1+1][i+len]+sum[i+len]-sum[i-1]); } } } temp=a[k]; a[k]=a[k+1]; a[k+1]=temp; if(dp[1][n]<sum1)sum1=dp[1][n]; } printf("%d\n",sum1); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-28 23:07:30