基本算法思想之穷举算法思想

文章向导

何为穷举, 何时使用穷举?
实例1:婚礼上的谎言
实例2:鸡兔同笼问题

一、何为穷举,何时使用穷举?

1.穷举思想简述
  穷举法可谓是计算机程序设计中最经典也最为简单的一种算法,其依赖于计算机强大的计算能力来穷尽每一种可能存在的情况,从而达到问题的求解。另外,该法也被称之为暴力求解法;实际上如果你愿意的话,几乎大多数问题都可以转换为穷举求解的过程,但因为穷举算法的效率不高,所以它一般被用于一些没有明显规律可循的场合。
  
2.算法的执行流程
  在使用穷举法时,首先是明确问题答案的范围,以便在指定范围内搜索答案。指定范围以后,则可通过循环和条件判断的方式逐个验证每个答案,从而得出符合条件限定的正确答案。

二、实例1:婚礼上的谎言

1.问题描述
  3对情侣参加婚礼。新郎依次为A,B,C;新娘依次为X,Y,Z。有人想知道究竟谁与谁结婚,于是就问情侣中的三位,得到如下结果:A说他将和X结婚;X说她的未婚夫是C;C说他将和Z结婚。这人事后知道他们刚才所说都只是开玩笑的话。那么,究竟谁与谁结婚呢?

2.问题分析
  首先是明确问题答案的范围,即谁与谁配对。若用a=1,2,3分别表示新郎A与新娘(X,Y,Z)结婚;用b=1,2,3分别表示新郎B与新娘(X,Y,Z)结婚;同理用c=1,2,3分别表示新郎C与新娘(X,Y,Z)结婚。那么,自然则可得出循环的范围为1~3,同时也可发现应使用三重for循环来逐个进行穷举。
  范围明晰后,还得考虑条件判断语句中所填的表达式。这点也特别重要,因为判断语句中所填的表达式相当于一种为得出正确答案而设置的限定条件。如果没有充分挖掘问题中明面上或隐含起来的条件,那么求解得出的答案则极有可能是不正确的。但大多数情况下,想得到完整无缺的条件并非那么容易,而且也不是一次到位的,通常需要求解观察后再反过来优化判断条件。
  现通过表格的形式来理清题中所涉及的可利用的判断条件:
   在这里插入图片描述
  根据题目的描述,首先可以得出C与Y配对(即c==2),同时还知A不与X配对(即a!=1) 。通过上面这份表格,应该马上就能得出正确答案(既然C与Y配对,那么A只能与Z配对,最后剩下的自然就是B与X配对)。是的,这样确实能够分析出来,但你如何将这种思路告诉计算机呢?显然因将描述性的语言转换为具体的表达式放入if中。可在刚才的推理过程中,明显用到了超过两条的逻辑表达式,所以还有隐藏起来的判断条件:3个新郎不能互为配偶,即a!=b,b!=c,a!=c。
  
3.编码求解(C++实现)

#include<iostream>

using namespace std;

int main(int argc, char *argv[])
{
	for(int a = 1; a <= 3; a++){
		for(int b = 1; b <= 3; b++){
			for(int c = 1; c <= 3; c++){
				if(a != 1 && c == 2 && a != b && a != c && b != c) {
					//因为a,b,c的最大值都为3,所以只要减一就能保证最小为X,最大为Z
					printf("%c 将嫁给 A\n",'X'+a-1); 
					printf("%c 将嫁给 B\n",'X'+b-1);
					printf("%c 将嫁给 C\n",'X'+c-1); 
				}
			}	
		}
	}		
	return 0;
}

三、实例2:鸡兔同笼问题

1.问题描述
  鸡兔同笼问题是我国古代《孙子算经》中一个非常著名的问题,此题也经常出现在如今小学奥数的练习中。算经的原文记载为:今有鸡兔同笼,上有三十五头,下有九十四足,问鸡兔各几何?
  
2.问题分析
  实际上这个问题列方程组就能够轻易求解,但我们现在尝试用穷举法来解决它。首先,明确问题答案的范围,由题可知鸡或兔的数量介于(0,35)这个区间内,且为整数。然后,考虑穷举时所给出的条件判断语句该为什么?分析后发现,题中还有关于腿的数量条件为使用,故可将鸡的数量2+兔的数量4=总腿数作为判断语句中所填的表达式。
  
3.编码求解(C++实现)

1). 穷举法

#include<iostream>

using namespace std;

int chick_rabbit(int head, int foot, int& chick, int& rabbit)
{
	int ret = 0,i,j; //i,j分别控制鸡和兔的数目变化(循环中)
	
	for(i = 0; i <= head; i++){
		j = head-i;
		if(i*2+j*4 == foot){
			ret = 1;
			chick = i;
			rabbit = j;
		}
	}
	
	return ret;
}

int main()
{
	int chick,rabbit,head,foot;
	int ret;
	
	cout<<"<穷举法解决鸡兔同笼问题>\n";
	cout<<"请分别输入头的数量和腿的数量:\n";
	cin>>head>>foot;
	if(head<=0 || foot<=0){
		cout<<"error!\n";
		return 0;
	}
	
	ret = chick_rabbit(head,foot,chick,rabbit);  //穷举后返回结果
	if(ret){
		printf("鸡的数量:%d  兔的数量:%d\n", chick, rabbit);
	} else{
		cout<<"No answer\n";
	}
	
	return 0;
}

2). 先化简再求解
  前面已经分析过了,其实通过解线性方程组的方式来化简此问题。分析可知chick+rabbit=head, chick2+rabbit4=foot,解此线性方程组后则可得出chick和rabbit的数量。嗯~确实迅速有力,但得注意若将此思路转换为具体的计算机程序,还得考虑下用if语句处理异常情况以及边界情况,也就是还得再加限制才能得出正确答案。

#include<iostream>

using namespace std;

int main()
{
	int chick,rabbit,head,foot;
	int ret;
	
	cout<<"请分别输入头的数量和腿的数量:\n";
	cin>>head>>foot;
	
	chick = (4*head - foot)/2;
	rabbit = head - chick;

	if(foot%2==1 || chick < 0 || rabbit < 0){  //总腿数肯定为偶数
		cout<<"No answer\n";
	}else{
		printf("鸡的数量:%d  兔的数量:%d\n", chick, rabbit);
	}
	
	return 0;
}

<求解结果>
在这里插入图片描述

参阅资料
C++ primer
C语言编程282例
C/C++常用算法手册

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值