相关代码:
#include<stdio.h>
#define M 200
int sum (int x,int y,int m[200][200]){
int all=0;
int i;
for (i=x;i<=y;i++)
all+= m[i][i];
return all;
}
void getMax(int n,int m[200][200],int s[200][200]){//n表示数组的长度,m为一个数组(记录每一段的最大得分),s记录每一段的额分界点
int i;
int j;
int r;
int k;
int t;
for(r=2;r<=n;r++)
for(i=1;i<=n-r+1;i++){
j=i+r-1;
m[i][j] =m[i][i]+m[i+1][j]+sum(i,j,m);
s[i][j]=i;
for(k=i+1;k<j;k++){
t=m[i][k] +m[k+1][j]+sum(i,j,m);s
if(t>m[i][j]){
m[i][j]=t; // 记录从i到j最大的得分
s[i][j] =k; //记录分界点
}
}
}
}
void getMin(int n,int m[200][200],int s[200][200]){//n表示数组的长度,m为一个数组(记录每一段的最大得分),s记录每一段的额分界点
int i;
int j;
int r;
int k;
int t;
for(r=2;r<=n;r++)
for(i=1;i<=n-r+1;i++){
j=i+r-1;
m[i][j] =m[i][i]+m[i+1][j]+sum(i,j,m);
s[i][j]=i;
for(k=i+1;k<j;k++){
t=m[i][k] +m[k+1][j]+sum(i,j,m);
if(t<m[i][j]){
m[i][j]=t; // 记录从i到j最小的得分
s[i][j] =k; //记录分界点
}
}
}
}
int main(){
int n;//石子的堆数
int m[M][M];
int s[M][M];
int i;
printf("请输如石子的堆数\n");
scanf("%d",&n);
printf("输入每一堆石子的数量\n");
for(i=1;i<=n;i++){
scanf("%d",&m[i][i]); //在此处单独列出来是为了付初值
}
getMax(n,m,s);
printf("\n最大得分%d",m[1][n]-sum(1,n,m));
getMin(n,m,s);
printf("\n最小得分%d",m[1][n]-sum(1,n,m));
}
问题分析:
这个问题可以通过分治法来解决,也可以通过动态规划的方式来解决。再这里介绍动态规划的方式来解决问题。动态规划的两个重要因素是重叠自问题性质和最优子结构。
1.当问题的最优解包含了其子问题的最优解时,称为问题具有最优子结构性质。
2.重叠子问题:再用递归法从顶向下解决问题时,每次产生的子问题并不是新问题,有些新问题被反复计算多次。
对于最小得分, 解决问题时可以自下向上解决。首先得到任意一堆的最小得分,然后在此基础上得到任意两队最小的分,依次类推。最终得到问题的解。对于最大得分的分析方法也一样。