• 算法设计思想


    程序=数据结构+算法+程序设计语言

    项目=程序+项目管理+质量控制+代码规范

        首先根据输入输出数据设计数据结构,再次设计相应的算法,最后使用某种编程语言。数据结构是算法实现的基础,算法依赖数据结构快速实现,二者相辅相承。

    1.递推思想

      顺推法

        假设有一对兔子,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?即斐波那契数列。

        使用顺推法计算,F(n)=F(n-1)+F(n-2)。最后F(n-1)/F(n)=>0.618即黄金分割比。

         逆推法

        例如:假设父亲为小龙一次性存入大学的生活费,只容许其每个月初取出1000供下个月使用,考虑月利息为0.71%,且银行在每月最后一天才计算利息计入本金。问开学时应该存多少钱。思想:

           第48个月,月初时,账户剩余F(48)=1000
             第47个月,月初时,账户剩余F(47)=(1000/(1+0.0071))+1000=F(48)/(1+0.0071)+1000
             第46个月,月初时,账户剩余F(46)=F(47)/(1+0.0071)+1000
             ............

        使用逆推,最终得到F(1)

    2.穷举思想

       满足2个条件:

            ⑴ 候选答案可数
            ⑵ 候选答案有确定的集合(便于使用条件判断语句和循环语句)

       例如:任意输入A,B,C,D,E,遍历加减乘除运算符,使“A( )B( )C( )D( )E =F”等式成立。思想:设定left,rigtht保存临时结果。left保存上次运算的结构,即下次运算的左侧,right保存下次将参加运算的数据,即下次运算的右侧内容。倘若为乘或除,直接运算right,倘若为加减,保存当前运算符,然后检查下一个运算符。若下一运算符为乘除,直接计算j结果保存至right,反之,计算left=left+flag*right。Operator[i]=0-4分别表示加减乘除。代码如下:

    #include"iostream"
    using namespace std;
    void print(int num[5],int Operator[4],int answer)//输出某个解决方案
    {
    	int i=0;
    	char index[4]={'+','-','*','/'};
    	cout<<num[0];
    	while(i<4)
    	  {cout<<index[Operator[i]];cout<<num[i+1];i++;}
    	cout<<"="<<answer<<endl;
    }
    void findSolution(int num[5],int answer)//嵌套循环遍历所有的解决方案
    {
    	int count=0;//计算器
    	int flag;//1=+,-1=-
    	int Operator[4];
    	double left,right;//切记此处一定定义为double
    
    	//嵌套遍历
    	for(Operator[0]=0;Operator[0]<4;Operator[0]++) 
    		if(Operator[0]<3||num[1]!=0) //当为除的时候,运算数不为0
    		  for(Operator[1]=0;Operator[1]<4;Operator[1]++)
    			if(Operator[1]<3||num[2]!=0)
    			  for(Operator[2]=0;Operator[2]<4;Operator[2]++)
    				if(Operator[2]<3||num[3]!=0)							
    				 for(Operator[3]=0;Operator[3]<4;Operator[3]++)
    					if(Operator[3]<3||num[4]!=0)
    					  {left=0;right=num[0];flag=1;
    						for(int i=0;i<4;i++)
    						{
    							switch(Operator[i])
    							{
    							    case 0:
    									 left=left+flag*right;//运算的是当前符号之前2个数
    									 right=num[i+1];
    									 flag=1;//保存当前符号
    									 break;
    								case 1:
    									left=left+flag*right;//运算的是当前符号的前2个数
    									right=num[i+1];
    									flag=-1;//保存当前符号,在后序操作有优先运算符的时候起作用
    									break;
    								case 2:
    									right=right*num[i+1];
    									break;
    								case 3:
    									 right=right/num[i+1];
    									 break;
    							}
    						}
    					    if(left+flag*right==answer)
    					          {count++;cout<<count<<":";print(num,Operator,answer);}
    	               }
    	if(count)
    	     cout<<"总共有"<<count<<"种方案"<<endl;
    	else
    	     cout<<"无有效解决方案,请重新输入"<<endl;
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
        cout<<"输入6个数,最后一个数为目标结果"<<endl;
        int num[5],answer;
        for(int i=0;i<5;i++) cin>>num[i];
        cin>>answer;
        findSolution(num,answer);
        return 0;
    }

    3.递归思想

          使用递归算法应该注意:

           ⑴必须有明确的递归结束条件即递归出口
           ⑵递归显得简洁但是运行效率低,主要反映在占存储空间
           ⑶递归过程中次数过多可能导致栈溢出(系统将每一次递归调用的返回点、局部变量等存入系统的栈中,      

       例如:10进制转换为任意进制。

    void Convert(vector<int> &ans,int number,int n)
    {
            if(!number) return;
    	else
    	   {ans.push_back(number%n);
    	   Convert(ans,number/n,n);}
    }

    4.分治思想

               分治算法和递归算法常常是紧密结合使用的。将一个问题分成几个子问题,然后将几个子问题的答案合并起来就是上一级的答案。一般具有以下特征的问题,可用分治法解答:

           ⑴可以分解成若干小的问题
           ⑵当分界到某种规模时,极易求解
           ⑶合并子问题的解可以得到求解问题的解
           ⑷子问题之间的解相互独立

       例如:在《算法导论》第三版的40页提到这样的问题,重新解释该问题,即为求解某个一维矩阵中,相加值最大的子矩阵。这里使用分治法基于以下策略思考。谭若在矩阵中设立标号mid。那么这个子矩阵要么完全在mid之前或者之后,要么横跨mid,每一级分治中,都寻找这样的3个子数组然后比较大小进行决策。代码如下:

    #include"iostream"
    #include"cmath"
    using namespace std;
    
    typedef struct submax
    {int low,high,maxsum;}SubArray;
    
    SubArray FindCrossingMax(int data[],int length,int low,int middle,int high)//寻找跨越middle的最大子数组
    {
        int present_left_sum=data[middle],left_max=data[middle];//寻找最大左子数组
    	int left_label=middle;
    	for(int j=middle-1;j>=low;j--)
    	 {present_left_sum+=data[j];
    	   if(left_max<present_left_sum)
    	     {left_max=present_left_sum;left_label=j;}}
    
        int present_right_sum=data[middle+1],right_max=data[middle+1];//寻找最大右子数组
        int right_label=middle+1;
        for(int j=middle+2;j<=high;j++)
    	{present_right_sum+=data[j];
    	if(right_max<present_right_sum)
    	{right_max=present_right_sum;right_label=j;}}
    	
        SubArray max={left_label,right_label,left_max+right_max};//跨越最大子数组=左子数组(含mid)+最大右子数组(含mid+1)
    	return max;
    }
    SubArray FindMaxSubArray(int data[],int length,int low,int high)//寻找最大子数组
    {
    	if(high==low)
    		{SubArray max={low,high,data[low]};return max;}
    	else
    		{int mid=floor(((double)high+low)/2);
    	        SubArray leftmax=FindMaxSubArray(data,length,low,mid);//寻找最大左(相对middle)子数组
    		SubArray rightmax=FindMaxSubArray(data,length,mid+1,high);//寻找最大右(相对middle)子数组
    		SubArray crossingmax=FindCrossingMax(data,length,low,mid,high);//寻找跨越middle的最大子数组
    		  
    		  if(leftmax.maxsum>=rightmax.maxsum&&leftmax.maxsum>=crossingmax.maxsum)
    			  return leftmax;
    		  else if(rightmax.maxsum>=leftmax.maxsum&&rightmax.maxsum>=crossingmax.maxsum)
    			  return rightmax;
    		  else
    			 return crossingmax;
    	    }
    }
    
    SubArray FindMaxSubArray(int data[],int length)//非递归法计算最大子数组
    {
    	int max=data[0];
    	int low=0,high=0;//初始化
    	for(int i=1;i<length;i++)
    	    {int present_sum=data[i],present_max=data[i];
    	     int label=i;
    		  for(int j=i-1;j>-1;j--)
    		      {present_sum+=data[j];
    			   if(present_max<present_sum)
    			      {present_max=present_sum;label=j;}}
    		  if(present_max>max)
    		       {max=present_max;low=label;high=i;}  
    	     }
    	SubArray maxarray={low,high,max};
    	return maxarray;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int  data[]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
    	SubArray max=FindMaxSubArray(data,sizeof(data)/sizeof(int),0,sizeof(data)/sizeof(int)-1);//分治法
    	SubArray max=FindMaxSubArray(data,sizeof(data)/sizeof(int));//非分治法
    	for(int i=max.low;i<=max.high;i++)
    	  cout<<data[i]<<" ";
    
    	return 0;
    }

    5.贪婪思想

          解为局部最优解。但对大部分问题,该解基本上近似整体最优解。贪婪算法基于当前初始解,采取逐步逼近的策略,不需要回溯。该算法存在以下问题

          ⑴不能保证解最优
          ⑵不能用来求最大最小解问题
          ⑶只能满足某些约束条件可行解的范围。

        一般实现策略如下:

          解初始化;
          while(尚未达到可行解总目标)
             求可行解的一个解元素;
          所有元素组成一个初始解;

        

    6.试探思想

    7.模拟思想


  • 相关阅读:
    ini_set /ini_get函数功能-----PHP
    【转】那个什么都懂的家伙
    word 2007为不同页插入不同页眉页脚
    August 26th 2017 Week 34th Saturday
    【2017-11-08】Linux与openCV:opencv版本查看及库文件位置等
    August 25th 2017 Week 34th Friday
    August 24th 2017 Week 34th Thursday
    August 23rd 2017 Week 34th Wednesday
    August 22nd 2017 Week 34th Tuesday
    August 21st 2017 Week 34th Monday
  • 原文地址:https://www.cnblogs.com/engineerLF/p/5393120.html
Copyright © 2020-2023  润新知