简析穷举算法,及其简单应用
穷举概述
- 穷举法又称列举法,其基本思想是逐一列举问题所涉及的所有情况。
- 穷举法常用于解决“是否存在”或“有多少种可能”等问题。
- 应用穷举法时应注意对问题所涉及的有限种情形须一一列举,既不能重复,又不能遗漏。
穷举通常应用循环结构来实现。在循环体中,应用选择结构实施判断筛选,求得所要求的解。
虽然巧妙和高效的算法很少来自穷举,但穷举设计作为一种常用的基础算法也很有意义:
(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}次"; //364次
echo "<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.