简析穷举算法,及其简单应用

简析穷举算法,及其简单应用

穷举概述

  • 穷举法又称列举法,其基本思想是逐一列举问题所涉及的所有情况。
  • 穷举法常用于解决“是否存在”或“有多少种可能”等问题。
  • 应用穷举法时应注意对问题所涉及的有限种情形须一一列举,既不能重复,又不能遗漏。
  • 穷举通常应用循环结构来实现。在循环体中,应用选择结构实施判断筛选,求得所要求的解。

    虽然巧妙和高效的算法很少来自穷举,但穷举设计作为一种常用的基础算法也很有意义:
    (1) 理论上,穷举可以解决可计算领域中的各种问题。尤其处在计算机计算速度非常高的今天,穷举的应用领域是非常广阔的。
    (2) 在实际应用中,通常要解决的问题规模不大,用穷举设计的算法其运算速度是可以接受的。此时,设计一个更高效率的算法代价不值得。
    (3) 穷举可作为某类问题时间性能的底限,用来衡量同样问题的更高效率的算法。

首先我们来看一个经典的例子:

百鸡百钱问题:
已知:公鸡5元一只,母鸡3元一只,小鸡一元3只。现用100元钱买了100只鸡。
问:公鸡母鸡小鸡各几只?(请考虑尽可能高效的方法)

实际上上面的问题直接用数学的方法是不容易解出来的,因为未知数的个数多余方程的个数。这时就可以用到穷举法,列出所有的可能性。

分析:
假设0只公鸡,0只母鸡,0只小鸡。结果???
假设0只公鸡,0只母鸡,1只小鸡。结果???
假设0只公鸡,0只母鸡,2只小鸡。结果???
......
假设0只公鸡,1只母鸡,0只小鸡。结果???
假设0只公鸡,1只母鸡,1只小鸡。结果???
假设0只公鸡,1只母鸡,2只小鸡。结果???
......
......
假设1只公鸡,0只母鸡,1只小鸡。结果???
假设1只公鸡,0只母鸡,2只小鸡。结果???
假设1只公鸡,0只母鸡,3只小鸡。结果???
......
......
......
假设100只公鸡,100只母鸡,100只小鸡。结果???
以上共有101*101*101(即1030301)种可能情况。

    这种思想,就是穷举思想,适合:问题的答案可能没有很直接的逻辑推理,但可以将所有“可能答案”都罗列出来,并且具有一定的规律性。
//原始思路:(穷举)
$count1 = 0;
for($gongji = 0; $gongji <= 100; ++ $gongji){
    for($muji = 0; $muji <= 100; ++ $muji){
        for($xiaoji = 0; $xiaoji <= 100; ++ $xiaoji){
            $shuliang = $gongji + $muji + $xiaoji;
            $zongjia = ($gongji * 5) + ($muji * 3) + ($xiaoji / 3);
            if( ($zongjia == 100) && ($shuliang == 100) ){
                echo "<br />公鸡有{$gongji}只,母鸡有{$muji}只,小鸡有{$xiaoji}只。";    
            }
            ++ $count1;    //计算的次数
        }
    }
}

echo "<br />总共计算了{$count1}次";  //1030301次,即101^3
echo "<hr />";

虽然对于计算机来说计算1030301次并不困难,但我们可以对上面的代码进行优化,尽可能的提高效率。

//优化1$count2 = 0;
for($gongji = 0; $gongji <= 100/5; ++ $gongji){ //考虑公鸡的价格
    for($muji = 0; $muji <= 100/3; ++ $muji){    //考虑母鸡的价格
        //for($xiaoji = 0; $xiaoji <= 100; ++ $xiaoji){
            $xiaoji = 100 - ($gongji + $muji); //公鸡母鸡的数量确定了,那么小鸡的数量也就确定了
            $zongjia = ($gongji * 5) + ($muji * 3) + ($xiaoji / 3);
            if( $zongjia == 100 ){
                echo "<br />公鸡有{$gongji}只,母鸡有{$muji}只,小鸡有{$xiaoji}只。";   
            }
            ++ $count2;    //计算的次数
        //}
    }
}

echo "<br />总共计算了{$count2}次";  //714次,优化了不少
echo "<br />";
//优化2$count3 = 0;
for($gongji = 0; $gongji <= 100/5; ++ $gongji){    //考虑公鸡的价格
    for($muji = 0; $muji <= (100-$gongji*5)/3; ++ $muji){ //考虑母鸡的价格,以及公鸡所花掉的钱
        //for($xiaoji = 0; $xiaoji <= 100; ++ $xiaoji){
            $xiaoji = 100 - ($gongji + $muji); //公鸡母鸡的数量确定了,那么小鸡的数量也就确定了
            $zongjia = ($gongji * 5) + ($muji * 3) + ($xiaoji / 3);
            if( $zongjia == 100 ){
                echo "<br />公鸡有{$gongji}只,母鸡有{$muji}只,小鸡有{$xiaoji}只。";   
            }
            ++ $count3;    //计算的次数
        //}
    }
}

echo "<br />总共计算了{$count3}次";  //364echo "<br />";
//优化3:
$count4 = 0;
for($gongji = 0; $gongji <= 100/5; ++ $gongji){    //考虑公鸡的价格
    for($muji = 0; $muji <= (100-$gongji*5)/3; ++ $muji){ //考虑母鸡的价格,以及公鸡所花掉的钱
        //for($xiaoji = 0; $xiaoji <= 100; ++ $xiaoji){
            $xiaoji = 100 - ($gongji + $muji); //公鸡母鸡的数量确定了,那么小鸡的数量也就确定了
            if($xiaoji % 3 != 0){//考虑小鸡的数量应该是3的倍数,价钱才能是“整数”
                continue;   //如果条件成立,直接跳出本次循环,后面的不再运算
            }
            $zongjia = ($gongji * 5) + ($muji * 3) + ($xiaoji / 3);
            if( $zongjia == 100 ){
                echo "<br />公鸡有{$gongji}只,母鸡有{$muji}只,小鸡有{$xiaoji}只。";   
            }
            ++ $count4;    //计算的次数
        //}
    }
}

echo "<br />总共计算了{$count4}次";  //121次

再来看下面一个例子:

数学问题:
有i,j,k,m,n五个字母分别代表0~9的数字,满足下面条件:
求i,j,k,m,n的实际值
    i  j  k  m  n
*                  i 
------------------------
 n  n  n  n  n  n
<style>
div{ width:300px; position:relative;}
div span{ margin:10px;}
</style>
<script>
window.onload = function(){
    var aP = document.getElementsByTagName('p');
    var aSpan1 = aP[0].getElementsByTagName('span');
    var aSpan2 = aP[1].getElementsByTagName('span');
    var aSpan3 = aP[2].getElementsByTagName('span');


    for(var i=1;i<=9;i++){
        for(var j=0;j<=9;j++){
            for(var k=0;k<=9;k++){
                for(var m=0;m<=9;m++){
                    for(var n=0;n<=9;n++){

                        var a = 10000*i + 1000*j + 100*k + 10*m + n;
                        var b = i;
                        var c = n*111111;

                        if(a*b==c){
                            aSpan1[0].innerHTML = i;
                            aSpan1[1].innerHTML = j;
                            aSpan1[2].innerHTML = k;
                            aSpan1[3].innerHTML = m;
                            aSpan1[4].innerHTML = n;

                            aSpan2[0].innerHTML = i;

                            for(var x=0;x<aSpan3.length;x++){
                                aSpan3[x].innerHTML = n;
                            }
                        }

                    }
                }
            }
        }
    }

};


</script>
</head>

<body>
<div>
<p style="margin-left:35px;">
<span>i</span><span>j</span><span>k</span><span>m</span><span>n</span>
</p>
<p>*   
<span style=" position:absolute; top:30px; left:180px;">i</span>
</p>
<hr />
<p>
<span>n</span><span>n</span><span>n</span><span>n</span><span>n</span><span>n</span>
</p>
</div>
</body>

运行结果为:

    7  9  3  6  5
*                  7 
------------------------
 5  5  5  5  5  5

也就是i=7, j=9, k=3, m=6, n=5.
即79365*7=555555.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值