算法详解(三):分而治之-金块问题

一:算法设计思想

1.1 分治法求解问题的过程
  • 将整个问题分解为若干个小问题后分而治之,如果分解的子问题还能够继续分解,则反复使用分治策略将问题继续划分,直到无法再继续分解为止,必要的时候合并这些小问题的解,就能够获得大问题的解。
  • 算法的特征可以理解为递归的过程,其中可以分为三个步骤
  1. 分解:将原问题划分为若干个规模较小的,相互独立,与原问题形式相同的子问题。
  2. 解决:若子问题规模较小且比较容易解决,则直接求解,否则则继续划分为较小的部分。
  3. 合并:将已经求解的各个子问题的解逐步合并为原问题的解。
1.2 适用范围
  • 求解问题的规模为n且取值相当大的问题,使用蛮力策略效率得不到保证,如果满足下面的条件,就能够使用分治法求解
  1. 能将这n个数据划分为k个不同的子集,并且k个子集又能够独立求解的子问题,其中1<k<=n
  2. 分治法得到的子问题与原问题有相似的结构,便于利用递归和循环机制
  3. 在求解出这些子问题的解后,就能够推出原问题的解

二:实际问题

2.1 金块问题
2.1.1 问题描述
  • 老板有一袋金块(共n块,n是2的幂(n≥2)),最优秀的雇员得到其中最重的一块,最差的雇员得到其中最轻的一块。假设有一台比较重量的仪器,希望用最少的比较次数找出最重和最轻的金块。参考链接
2.1.2 蛮力法
2.1.2.1 算法设计
  • 对金块进行逐个查找,先拿到两块中比较重的那一个,然后留下来与下一块比较,直到全部比较完成,就找到,算法类似于一趟选择排序
2.1.2.2 代码
def minmax(a, n):
    max = a[0]
    min = a[0]
    for i in range(2, n):
        if max<a[i]:
            max = a[i]
        if min > a[i]:
            min = a[i]
    return max, min
2.1.3 分治法
  • 将数据分为两个组,目的是选择其中的最小值和最大值
  • 递归分解知道每个元素的个数<=2可简单的找到最大的值和最小的值
  • 回溯时合并子问题的解,在两个子问题的解中大者取大,小者取小,合并为当前问题的解
  • 代码
#include<stdio.h> 
float min(float x,float y)
{    
    if(x<y)     
        return x;  
    else     
        return y; 
}
 
float max(float x,float y)
{    
    if(x>y)      
        return x;  
    else     
        return y; 
}
 
float Find_min(float A[],int left,int right)
{   
    float la,ma,ra;
    if(left==right) 
    {
        float min;
        min=A[right];
        return min;
    }
    if(right-left==1.0) 
    {
        la=A[left];
        ra=A[right];
        return(min(la,ra));
    }
    if(right-left>1.0)
    {
        ma=(left+right)/2.0;      
        la=Find_min(A,left,ma); 
        ra=Find_min(A,ma,right);
        return(min(la,ra));     
    }       
}   
float Find_max(float A[],int left,int right)
{   
    float la,ma,ra;   
    if(left==right)
    {    
        float max;    
        max=A[right];    
        return max;   
    }    
    if(right-left==1.0)    
    {    
        la=A[left];    
        ra=A[right];    
        return(max(la,ra));     
    }      
    if(right-left>1.0)
    {       
        ma=(left+right)/2.0;      
        la=Find_max(A,left,ma);      
        ra=Find_max(A,ma,right);      
        return(max(la,ra));     
    }       
}   
int main()
{    
    float A[100];  
    int n;     
    float min;
    float max;   
    printf("请输入金块数目:\n");   
    scanf("%d",&n);   
    printf("请输入%d块金子的重量:\n",n);   
    for(int i=0;i<n;i++)   
        scanf("%f",&A[i]); 

    printf("最重的金块:");   
    max=Find_max(A,0,n-1);    
    printf("%.1f\t\t",max);      
	   
    printf("最轻的金块:");   
    min=Find_min(A,0,n-1);     
    printf("%.1f",min); 
    printf("\n"); 
    return 0;
}


  • 4
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值