石子合并问题
在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选择相邻的两堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。
样例输入
4
4 4 5 9
样例输出
54 43
解:
石子合并问题:
利用p[i][j]存放石子i~j合并得到的石子数目
将dp[i][j] 存放石子i~j合并得到的积分
所以p[i][j]先使用init进行初始化
计算积分的时候与矩阵连乘相似,先初始i~i与i+1~j合并
将i~j的石子堆合并,转变为i~k与k+1~j进行合并,再加上石子数量
找出最小值作为dp[i][j];
因为这是一个环,所以,以上情况需要进行n次,每次石子堆进行改变,
找出最小,最大值
#include <stdio.h>
#include <string.h>
#define MAX(a,b) a>b?a:b
#define MIN(a,b) a<b?a:b
int p[100][100]={0};
int dp[100][100];
int n;
void init(int *a){
for(int i=1;i<=n;i++)
{//
p[i][i]=a[i];
for(int j=i+1;j<=n;j++)
{//i~j合并就是i~j-1合并数目加上j的数目
p[i][j]=p[i][j-1]+a[j];
}
}
}
int Maxvalue(){
int i,j,r,k;
for(r=2;r<=n;r++)
{//合并的石子堆数
for(i=1;i+r-1<=n;i++)
{//开始合并的石子堆
j=i+r-1;//结束的堆
dp[i][j] = p[i][i]+dp[i+1][j] + p[i+1][j];
for(k=i+1;k<j;k++)
{
dp[i][j]=MAX(dp[i][j],dp[i][k]+dp[k+1][j] + p[i][k]+p[k+1][j]);
}
}
}
return dp[1][n];
}
int Minvalue(){
int i,j,r,k;
for(r=2;r<=n;r++)
{
for(i=1;i+r-1<=n;i++)
{
j=i+r-1;
dp[i][j] = p[i][i]+dp[i+1][j] + p[i+1][j];
for(k=i+1;k<j;k++)
{
dp[i][j]=MIN(dp[i][j],dp[i][k]+dp[k+1][j] + p[i][k]+p[k+1][j]);
}
}
}
return dp[1][n];
}
int main()
{
int a[100];
int max=0,min=9999999;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
memset(dp,0,sizeof(dp));
init(a);
int count=n;
while(count)
{//考虑环的问题
count--;
int tempmax = Maxvalue();
int tempmin = Minvalue();
if(tempmax>max)
max=tempmax;
if(tempmin<min)
min=tempmin;
int temp=a[1];
//执行完一次之后进行数组整体移动,达到环的目的
for(int i=1;i<n;i++)
a[i]=a[i+1];
a[n]=temp;
}
printf("MAX:%d\n",max);
printf("MIN:%d\n",min);
return 0;
}