枚举

枚举(一)

枚举就是根据提出的问题,列出该问题的所以可能的解,并在逐一列出的过程中,检验每个可能解是否是问题真正的解,如果是,就采纳这个解,如果不是就继续判断下一个。

枚举法一般比较直观,容易理解,但由于要检查所有可能的解,因此运行效率较低

能用枚举法解决的问题一般具有以下特征:

①解枚举范围是有穷的

②检验条件是确定的

枚举法的结构是:枚举范围循环+条件判断语句

例题1:某君说我的年龄是两位数,我比我的儿子大27岁,如果把我年龄的两位数交换位置,刚好就是我儿子的年龄

请你计算 某君的年龄一共有多少种可能情况?

分析

①年龄是两位数,则取值范围是[10,99]内的整数(解枚举范围是有穷的)

②把枚举年龄的个位数与十位数交换,如果发现刚好比原数字小27,那么它就是真正的解(检验条件是确定的)

则可以用枚举法

public class Main {

	
	public static void main(String[] args) {
		int total=0;
		for(int i=10;i<100;i++){
			int a=i%10;//计算出年龄的个位数
			int b=i/10;//计算出年龄的十位数
			if(i==a*10+b+27)
			{
				total++;
			}
		}
		System.out.println(total);
	}

}

例题2:如果一个三位数,它的每个位上的数字的三次幂之和等于它本身,那么我们就称这个数字是一个水仙花数,现在求出所有的水仙花数。

分析

①一个三位数,则取值范围是[100,999]内的整数(解枚举范围是有穷的)

②每个位上的数字的三次幂之和等于它本身(检验条件是确定的)

则可以用枚举法

public class Main {

	public static void main(String[] args) {
		
		for(int i=100;i<1000;i++)
		{
			int a=i/100;//百位
			int x=i%100;
			int b=x/10;//十位
			int c=x%10;//个位
			if(i==Math.pow(a,3)+Math.pow(b,3)+Math.pow(c,3))
			{
				System.out.println(i);
			}
		}
           
	}
}
枚举(二)

之前的枚举都是只枚举了一个变量的解,往往枚举的题目需要枚举很多变量,条件判断也会有很多繁琐的情况

例题3:

口+口=口

口-口=口

口x口=口

口/口=口 每个方块代表1-13中的数字,但不能重复,交换加法 乘法前后的操作数后算不同的方案,算一算,一共有多少种方案

public class Main {

	public static void main(String[] args) {
	
	int a1,a2,a3,a4,a5,a6,a7,a8;
	
	int[] vis;
	vis=new int[14];
	int tot=0;//记录合法的方案数
	for(a1=1;a1<=13;++a1)
	{
		vis[a1]=1;
		for(a2=1;a2<=13;++a2)
		{
			if(a1+a2>13||vis[a2]==1)
			{
				continue;
			}
			vis[a2]=1;
			vis[a1+a2]=1;
			for(a3=1;a3<=13;++a3)
			{
				if(vis[a3]==1)
				{
					continue;
				}
				vis[a3]=1;
			    for(a4=1;a4<=13;++a4)
			    {
			    	if(a3-a4<1||a3-a4>13||vis[a4]==1||vis[a3-a4]==1||a4==a3-a4)
			    	{
			    		continue;
			    	}
			    	vis[a4]=1;
			    	vis[a3-a4]=1;
			    	for(a5=1;a5<=13;++a5)
			    	{
			    		if(vis[a5]==1)
			    		{
			    			continue;
			    		}
			    		vis[a5]=1;
			    		for(a6=1;a6<=13;++a6)
			    		{
			    			if(a5*a6>13||vis[a6]==1||vis[a5*a6]==1||a6==a5*a6)
//注意先判断a5*a6的大小,如果先判断vis[a5*a6]==1则可能发生溢出,||表示如果一个条件是错误的,则其余的不会再判断
			    			{
			    				continue;
			    			}
			    			vis[a6]=1;
			    			vis[a5*a6]=1;
			    			for(a7=1;a7<=13;a7++)
			    			{
			    				if(vis[a7]==1)
			    				{
			    					continue;
			    				}
			    				vis[a7]=1;
			    				for(a8=1;a8<=13;a8++)
			    				{
			    					if(vis[a8]==1||a7<a8||a7%a8!=0||vis[a7/a8]==1||a8==a7/a8)
			    					{
			    						continue;
			    					}
			    					tot++;
			    				}
			    				vis[a7]=0;
			    			}
			    			vis[a6]=0;
			    			vis[a5*a6]=0;
			    		}
			    		vis[a5]=0;
			    	}
			    	vis[a4]=0;
			    	vis[a3-a4]=0;
			    }
			    vis[a3]=0;
			}
			vis[a2]=0;
			vis[a1+a2]=0;
		}
		vis[a1]=0;
	}

	
	
	System.out.println(tot);//输入 64
	
	
	
	}
	

}

例题:口口口+口口口=口口口 为1-9中的数字,不能重复,如173+286=459是正确的,请问一共有多少种合理的组合?

173+286=459 和286+173=459相同

public class Main {

	
	public static void main(String[] args) {
		 int a1,a2,a3,a4,a5,a6,a7,a8,a9;
		 int[] vis=new int[10];
		 int tot = 0;
		 for(a1=1;a1<=9;a1++)
		 {
			 vis[a1]=1;
			 for(a2=1;a2<=9;a2++)
			 {
				 if(vis[a2]==1)
				 {
					 continue;
				 }
				 vis[a2]=1;
				 for(a3=1;a3<=9;a3++)
				 {
					 if(vis[a3]==1)
					 {
						 continue;
					 }
					 vis[a3]=1;
					 for(a4=1;a4<=9;a4++)
					 {
						 if(vis[a4]==1)
						 {
							 continue;
						 }
						 vis[a4]=1;
						 for(a5=1;a5<=9;a5++)
						 {
							 if(vis[a5]==1)
							 {
								 continue;
							 }
							 vis[a5]=1;
							 for(a6=1;a6<=9;a6++)
							 {
								 if(vis[a6]==1)
								 {
									 continue;
								 }
								 vis[a6]=1;
								 for(a7=1;a7<=9;a7++)
								 {
									 if(vis[a7]==1)
									 {
										 continue;
									 }
									 vis[a7]=1;
									 for(a8=1;a8<=9;a8++)
									 {
										 if(vis[a8]==1)
										 {
											 continue;
										 }
										 vis[a8]=1;
										 for(a9=1;a9<=9;a9++)
										 {
											 if(vis[a9]==1)
											 {
												 continue;
											 }
											 if((a1*100+a2*10+a3)+(a4*100+a5*10+a6)==(a7*100+a8*10+a9))
											 {
												 tot++;
											 }
										 }
										 vis[a8]=0;
									 }
									 vis[a7]=0;
								 }
								 vis[a6]=0;
							 }
							 vis[a5]=0;
						 }
						 vis[a4]=0;
					 }
					 vis[a3]=0;
				 }
				 vis[a2]=0;
			 }
			 vis[a1]=0;
		 }
            System.out.print(tot/2);
	}

}
小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。

有一次,老师出的题目是:36 x 495 = ?

他却给抄成了:396 x 45 = ?

但结果却很戏剧性,他的答案竟然是对的!!

因为 36 * 495 = 396 * 45 = 17820

类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54

假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)

能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?

请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。

满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数。

答案直接通过浏览器提交。

注意:只提交一个表示最终统计种类数的数字,不要提交解答过程或其它多余的内容。

能满足形如:ab * cde = adb * ce这样的算式一共有(5分)

public class Main {

	
	public static void main(String[] args) {
		 int a1,a2,a3,a4,a5;
		 int[] vis=new int[11];
		 int tot = 0;
		 for(a1=1;a1<=9;a1++)
		 {
			 vis[a1]=1;
			 for(a2=1;a2<=9;a2++)
			 {
				 if(vis[a2]==1)
				 {
					 continue;
				 }
				 vis[a2]=1;
				 for(a3=1;a3<=9;a3++)
				 {
					 if(vis[a3]==1)
					 {
						 continue;
					 }
					 vis[a3]=1;
					 for(a4=1;a4<=9;a4++)
					 {
						 if(vis[a4]==1)
						 {
							 continue;
						 }
						 vis[a4]=1;
						 for(a5=1;a5<=9;a5++)
						 {
							 if(vis[a5]==1)
							 {
								 continue;
							 }
							 if((a1*10+a2)*(a3*100+a4*10+a5)==(a1*100+a4*10+a2)*(a3*10+a5))
							 {
								 tot++;
							 }
						 }
						 vis[a4]=0;
					 }
					 vis[a3]=0;
				 }
				 vis[a2]=0;
			 }
			 vis[a1]=0;
		 }
        System.out.print(tot);
	}

}


二进制枚举子集

给定一个集合,枚举所以可能的子集。可以用二进制法。用二进制的一位表示集合对应某一元素的选取状态,1表示选取,0表示不选

位运算

A&B 与 (全为1才是1)

A|B   或 (有一个1就是1)

A^B  异或 (两者同为0或1时才是0,其他为1)

位运算符中有两种操作,左移<<和右移>>

对于A<<B,表示A转换为二进制后,向左移动B位,(在末尾添加B个0)

对于A>>B,表示A转换为二进制后,向右移动B位,(删除末尾的B位)

比如2<<2,2转换为二进制为 01,10左移动2位,就变成了二进制1000,转换为十进制是8,即2<<2=8

例4:

诗人李白,一生好饮酒,逢店加一倍,遇花喝一斗。一共遇店10次,遇花5次,已知最后一次遇到的是花,他正好把酒喝光了,请你计算遇到花和店的次序,有多少种可能的方案。

解法:用二进制枚举,已知遇店10次,遇花5次,并且最后一次遇到的花,正好把酒喝完,把遇到店作为二进制中的1,遇到花作为二进制中的0,已知最后一次遇到的是花,所以我们判断枚举的结果是否刚好有5个1和9个0,那我们就枚举出14位二进制的所有可能并加以判断,判断思路为是否有5个1和9个0,并且最终酒刚好剩一斗。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值