在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。
#include <stdio.h>
#define N 100
#define INF 65536
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
int MAX,MIN,a[N],n;
int dp[N][N][2];//0代表最小值,1代表最大值
int total(int i, int j)
{
int total=0;
for(int k=i;k<=j;k++)
total += a[k];
return total;
}
void function()
{
int i,j,k,len;
for(i=1;i<=n;i++)
dp[i][i][0] = dp[i][i][1] = 0;
for(len=2;len<=n;len++)//有几堆合并
for(i=1;i<=n-len+1;i++)//从第几堆开始
{
j=i+len-1;//到第几堆
dp[i][j][0] = INF;
dp[i][j][1] = -INF;
for(k=i;k<j;k++)
{
if(dp[i][k][0]+dp[k+1][j][0]+total(i,j) < dp[i][j][0])
dp[i][j][0]=dp[i][k][0]+dp[k+1][j][0]+total(i,j);
if(dp[i][k][1]+dp[k+1][j][1]+total(i,j) > dp[i][j][1])
dp[i][j][1]=dp[i][k][1]+dp[k+1][j][1]+total(i,j);
}
}
MAX = max(MAX,dp[1][n][1]);
MIN = min(MIN,dp[1][n][0]);
}
int main()
{
int i;
MAX = -INF, MIN = INF;
printf("输入堆的个数:");
scanf("%d",&n);
printf("输入每堆石子个数:");
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
function();
for(i=2;i<=n;i++)//圆圈拆成一根根的直线
{
int last = a[1];
for(int j=2;j<=n;j++)
a[j-1] = a[j];
a[n] = last;
function();
}
printf("最大值为:%d\n",MAX);
printf("最小值为:%d\n",MIN);
return 0;
}
还有一种空间换时间方法,圆圈用两倍直线代替,比如圆圈长度为N,则用2N的数组表示
#include <stdio.h>
#define N 100
#define INF 65536
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
int MAX,MIN,a[N],n;
int dp[N][N][2];//0代表最小值,1代表最大值
int total(int i, int j)
{
int total=0;
for(int k=i;k<=j;k++)
total += a[k];
return total;
}
void function()
{
int i,j,k,len;
for(i=1;i<=2*n;i++)
dp[i][i][0] = dp[i][i][1] = 0;
for(len=2;len<=n;len++)//有几堆合并
for(i=1;i<=2*n-len+1;i++)//从第几堆开始
{
j=i+len-1;//到第几堆
dp[i][j][0] = INF;
dp[i][j][1] = -INF;
for(k=i;k<j;k++)
{
if(dp[i][k][0]+dp[k+1][j][0]+total(i,j) < dp[i][j][0])
dp[i][j][0]=dp[i][k][0]+dp[k+1][j][0]+total(i,j);
if(dp[i][k][1]+dp[k+1][j][1]+total(i,j) > dp[i][j][1])
dp[i][j][1]=dp[i][k][1]+dp[k+1][j][1]+total(i,j);
}
}
for(i=1;i<=n;i++)
{
if(dp[i][i+n-1][0] < MIN)
MIN = dp[i][i+n-1][0];
if(dp[i][i+n-1][1] > MAX)
MAX = dp[i][i+n-1][1];
}
}
int main()
{
int i;
MAX = -INF, MIN = INF;
printf("输入堆的个数:");
scanf("%d",&n);
printf("输入每堆石子个数:");
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=n+1;i<=2*n;i++)//这里不同
a[i] = a[i-n];
function();
printf("最大值为:%d\n",MAX);
printf("最小值为:%d\n",MIN);
return 0;
}