合并果子(续)
合并果子(续)
前面说过一种合并果子是任意型的http://www.cnblogs.com/jiangjun/archive/2012/11/11/2765474.html
下面来看两种类型:直线型和圆形型
一、直线型
问题描述:
在一个直线上依次摆放N堆石(N≤100),现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
输入:堆数N及每堆的石子数(≤20),
选择一种合并石子的方案,使得做N-1次合并,得分的总和最小(或最大)
分析:和矩阵连乘类似,不能像任意型那样用贪心,那用DP求解
状态转移方程如下:

f[i][j]为第i堆石子到第j堆石子合并后的最少总分数,sum[i][j]表示第i堆石子到第j堆石子的总数量
思想大概就是这样的,代码就借用别人的,如下:
# include<stdio.h> #define inf 9999999 #define N 105 int sum[N]; int best[N][N]; int n,stone[N]; int min(int a,int b) { return a<b?a:b; } int getBest() { int i,v,j,k; int add; for(i=0;i<n;i++)//没有合并前花费为0 { best[i][i]=0; } for(v=1;v<n;v++)//需合并的长度 { for(i=0;i<n-v;i++) { j=i+v; best[i][j]=inf; add=sum[j]-(i>0?sum[i-1]:0);//做一点处理,但依旧是第i堆石子到第j堆石子的总数量 for(k=i;k<j;k++) { best[i][j]=min(best[i][j],best[i][k]+best[k+1][j]+add); } } } return best[0][n-1]; } int main() { int i; int best; scanf("%d",&n); for(i=0;i<n;i++) scanf("%d",&stone[i]); sum[0]=stone[0]; for(i=1;i<n;i++) { sum[i]=sum[i-1]+stone[i]; } best=getBest(); printf("%d\n",best); return 0; }
二、圆形型
问题描述:
在一个园形操场的四周摆放N堆石子(N≤100),现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
输入:堆数N及每堆的石子数(≤20),
选择一种合并石子的方案,使得做N-1次合并,得分的总和最小(或最大)
分析:这和上面的直线型比,需要考虑第一个和最后一个的合并,还要在原代码上作几点改变,①f(i, j)变成表示从第i个开始,合并后面j个得到的最优值;sum(i, j)变成表示从第i个开始直到i+j个的数量和 ②最后在返回值时,因为没有头,所以要全部遍历一遍
同样,DP状态转换方程如下:

f[i][j]为第i堆石子到第i+j堆石子合并后的最少总分数,sum[i][i+j]表示第i堆石子到第i+j堆石子的总数量
思想有了,代码就借用别人的,如下:
# include<stdio.h> #define inf 9999999 #define N 105 int sum[N]; int best[N][N]; int n,stone[N]; int min(int a,int b) { return a<b?a:b; } int sums(int i, int j) { if(i+j>=n) return sums(i,n-i-1)+sums(0,(i+j)%n); else return sum[i+j]-(i>0?sum[i-1]:0); } int getBest() { int i,j,k; int minnum; for(i=0;i<n;i++)//没有合并前花费为0 { best[i][i]=0; } for(j=1;j<n;j++)//需合并的长度 { for(i=0;i<n;i++) { best[i][j]=inf; for(k=0;k<j;k++) { best[i][j]=min(best[i][j],best[i][k]+best[(i+k+1)%n][j-k-1]+sums(i,j)); } } } minnum=best[0][n-1]; for(i = 0;i<n;i++)//因为没有头,所以要全部遍历一遍 { minnum=min(minnum,best[i][n-1]); } return minnum; } int main() { int i; int best; scanf("%d",&n); for(i=0;i<n;i++) scanf("%d",&stone[i]); sum[0]=stone[0]; for(i=1;i<n;i++) { sum[i]=sum[i-1]+stone[i]; } best=getBest(); printf("%d\n",best); return 0; }
浙公网安备 33010602011771号