2021-06-24

环形石子合并问题

1. 代码示例
下面展示 程序代码

#include<stdio.h>
#define N 100
    /*
    *求合并过程中
    *最少合并堆数目
    */
    int MatrixChain_min(int p[N],int n)//p[N]石子数,n石子堆数 
    {
        int m[N][N];              //定义二维数组m[i][j]来记录i到j的合并过成中最少石子数目(石子积分) 
         
        int min=0;                                                     
        for(int g = 1;g<=n;g++)
			m[g][g]=0;  //当一个单独合并时,m[i][i]设为0,表示没有积分。
                                                            
		for(int i=1;i<=n-1;i++)//当相邻的两堆石子合并时,此时的m很容易可以看出是两者之和。
		{
          int j=i+1;
          m[i][j]=p[i]+p[j];
        }
	                                                     
		for(int r=3; r<=n;r++)//当相邻的3堆以及到最后的n堆时,执行以下循环(r表示考虑到了多堆石子合并的所有情况) 
           for(int i=1;i<=n-r+1;i++)//i表示开始的那一堆,j表示最后的那一堆 
           {
               int j = i+r-1; //j总是距离i r-1的距离                           
               int fin=0;                                  
               for(int b=i;b<=j;b++)//当i到j堆石子合并时最后里面的石子数求和得fin(fin是所有的石子数) 
                   fin+=p[b];
  
               // 此时m[i][j]为i~j堆石子间以m[i][i]+m[i+1][j]+fin结果,这是其中一种可能,不一定是最优【】??? 
               //要与下面的情况相比较
  
                m[i][j] = m[i+1][j]+fin;//最初的积分情况 
  
               //除上面一种组合情况外的其他组合情况
               for(int k=i+1;k<j;k++)//进行比较 
               {
                   int t=m[i][k]+m[k+1][j]+fin;//后来情况的积分 
                   if(t<m[i][j])
                       m[i][j] = t;
  
               }
           }
            //最终得到最优解
           min=m[1][n]; //最小的情况赋值给min 
           return min;
          
    }
  
  /*
   *求合并过程中
   *最多合并堆数目
   **/
  
    int  MatrixChain_max(int p[N],int n)
    {
        int m[N][N];
    	int max=0;
        //一个独自组合时
    	for(int g = 1;g<=n;g++) 
			m[g][g]=0;
        //两个两两组合时
    	for(int i=1;i<=n-1;i++)
    	{
        	int j=i+1;
        	m[i][j]=p[i]+p[j];
    	}
  
        for(int r=3; r<=n;r++)
           for(int i=1;i<=n-r+1;i++)
            {
               int j = i+r-1;
               int sum=0;
               for(int b=i;b<=j;b++)
                   sum+=p[b];
                m[i][j] = m[i+1][j]+sum;
               
               for(int k=i+1;k<j;k++)
               {
                   int t=m[i][k]+m[k+1][j]+sum;
                   if(t>m[i][j])
                      m[i][j] = t;
 
              }
          }
 
          max=m[1][n];
          return max;
    }
    
 int main()
 {
       int stone[N];//每堆石子数 
       int min=0;//最小的分初始化 
       int max=0;//最大的分初始化 
       int n;//石子堆数 
       printf("请输入石子堆数:");
       scanf("%d",&n);
       for(int i=1;i<=n;i++){ 
       		printf("请输入第%d堆石子数:",i);
            scanf("%d",&stone[i]);
 		} 
       min= MatrixChain_min(stone,n);//传到子函数 
       max= MatrixChain_max(stone,n);//传到子函数 
 
       //因为题目要求圆的原因,要把所有情况都要考虑到,总共有n种情况。
       for(int j=1;j<=n-1;j++)
       {
            int min_cache=0;//积分最小情况 
            int max_cache=0;//积分最大情况
            int cache= stone[1];//
            for(int k=2;k<=n;k++)
            {
                stone[k-1]=stone[k];
            }
            stone[n]=cache;//
            min_cache= MatrixChain_min(stone,n);//
            max_cache= MatrixChain_max(stone,n);//
            if(min_cache<min)
               min=min_cache;//
            if(max_cache>max)
                max=max_cache;//
      }
    
    printf("最小得分:%d\n",min);
    printf("最大得分:%d\n",max);

     return 1;
 }

2. 产生的错误
(1)循环输入石子堆数代码错误
错误代码如下所示:
错误代码
更正后:
更正后
(2)代码运行结果错误
在起初代码运行成功时,进行了算法测试,分别输入1堆、2堆、3堆、5堆石子来验证算法准确性。
1堆石子运行结果:
一堆石子运行结果2堆石子运行结果:
二堆石子运行结果
3堆石子运行结果:
三堆石子运行结果
显而易见,2堆和3堆石子运行结果均错误。
感悟与体会
通过本次代码的编写与实现,我从中感悟到了很多。一个高效的程序不仅需要编程技巧,更需要合理的数据组织和清晰高效的算法。通过对课程的理论学习与实践,我掌握了许多经典的算法思想,思维创新能力和实践能力得到了有效的提高,并且一题多解的情况让我对不同的算法有了更加深刻的认识。本次算法实验题让我深刻感悟到了动态规划法的魅力,同时在程序设计过程中遇到的为你也会让我认识到自己的不足,实际实践之后,这些知识在我们今后的学习中将会得到更深层次的理解与应用。

猜你喜欢

转载自blog.csdn.net/weixin_53233197/article/details/118198659