石子合并问题

相关代码:

#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.重叠子问题:再用递归法从顶向下解决问题时,每次产生的子问题并不是新问题,有些新问题被反复计算多次。

     对于最小得分, 解决问题时可以自下向上解决。首先得到任意一堆的最小得分,然后在此基础上得到任意两队最小的分,依次类推。最终得到问题的解。对于最大得分的分析方法也一样。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值