实验2 穷举法的应用 1.简单枚举+2.猜数字

本文通过两个编程实例,探讨了如何在编程中使用穷举法和对排列的分析,分别解决除法表达式和猜数字问题。通过简化算法和分析问题本质,减少了枚举量,展示了暴力枚举在问题解决中的高效应用。
摘要由CSDN通过智能技术生成

1

目的:

1.理解穷举法

2.掌握排列的应用

实验内容:

 1.简单枚举

在枚举复杂对象之前,先尝试着枚举一些相对简单的内容,如整数、子串等。尽管暴力枚举不用太动脑筋,但对问题进行一定的分析往往会让算法更加简洁、高效。

提示7-1:即使采用暴力法求解问题,对问题进行一定的分析往往会让算法更简洁、高效。

例题7-1 除法(Division, UVa 725)

输入正整数n,按从小到大的顺序输出所有形如abcde/fghij= n的表达式,其中a~j恰好为数字0~9的一个排列(可以有前导0),2≤n≤79。

样例输入:

62

样例输出:

79546 / 01283 = 62

94736 / 01528 = 62

【分析】

枚举0~9的所有排列?没这个必要。只需要枚举fghij就可以算出abcde,然后判断是否所有数字都不相同即可。不仅程序简单,而且枚举量也从10!=3628800降低至不到1万,而且当abcde和fghij加起来超过10位时可以终止枚举。由此可见,即使采用暴力枚举,也是需要认真分析问题的。

 

编程思路

假设变量  x / y = n

定义长度为10的数组 int a[10];来统计x,y中各个数字出现的频率。

当 a[10] = {1,1,1,1,1,1,1,1,1,1}时,表示所有数字都出现了,即x和y符合我们的要求。这时输出结果。

#include <stdio.h>


//判断数字的位数 
int intlen(int nums){
	int i=0;
	while(nums > 0){
		nums = nums /10;
		i++;
	}
	return i;
}
//判断数组是否全为1 
int all_one(int a[],int x,int y){
	int i;
	int xx = x;
	
	if(intlen(x)>5){
		return 0;
	}
	// 统计x中数字出现的频率 
	for(i=0;i<intlen(xx);i++){
//		printf(" %d\n",x%10);
		a[x%10] = a[x%10] + 1;
		x = x / 10; 
	}
	
	//统计y中数字出现的频率 
	int yy = y;
	if (intlen(yy) <5){
		a[0] = 1;
	}
	
	for(i=0;i<intlen(yy);i++){
//		printf(" %d\n",y%10);
		a[y%10] = a[y%10] + 1;
		y = y / 10; 
	}
	
	//判断是否全为1 
	for(i=0;i<10;i++){
		if (a[i] != 1){
			return 0;
		}
	}
	return 1;
}

int main(){
	int n = 15;
	int i;
	int a[10];
	int y;
	int x;
	
	for(y=0;y<99999;y++){
		x = y * n;
		// 初始化数组 
		for(i=0;i<10;i++){
			a[i] = 0;
		}
		//判断是否全为1
		if (all_one(a,x,y) == 1){
			printf("%d / %d = %d\n",x,y,n);
		}
	}
	return 0;
}

n = 15的结果

2.猜数字

46*79=23*158

要求找出所有的乘法等式,并1-9个数字只能用一次。

编程思路

将一个九位数拆成4个数,如467923158 -》 46,79,23,158

然后将四个数字按上面的乘法相乘,判断是否符合要求,符合即输出。

这里要去掉两种情况,1.有零出现。2.数字重复出现。方法与上一题一样,统计各个数字出现的频率。

#include <stdio.h>

int intlen(int nums){
	int i=0;
	while(nums > 0){
		nums = nums /10;
		i++;
	}
	return i;
}


//判断是否符合要求 
int all_one(int* a_nums){
	int i;
	if (intlen(a_nums[0]) < 2 || intlen(a_nums[1]) < 2 || intlen(a_nums[2]) < 2 || intlen(a_nums[3]) < 3){
		return 0;
	}
	//初始化数组 
	int a[10];
	for (i=0;i<10;i++){
		a[i] = 0;
	}
	//统计数字出现的频率 
	for (i=0;i<4;i++){
		int x = a_nums[i];
		int xx = x;
		int j;
		for(j=0;j<intlen(xx);j++){
			a[x%10] = a[x%10] + 1;
			x = x / 10; 
		}		
	}
	//如果0出现,就去掉 
	if (a[0] == 1){
		return 0;
	}
	//判断是否全为1 
	for(i = 1;i<10;i++){
		if(a[i] != 1){
			return 0;
		}
	}
	return 1;
}

//拆分数字 
void get_nums(int num,int* a){
	int num1 = (num / 100000)/100;
	int num2 = (num / 100000)%100;
	int num3 = (num % 100000)/1000;
	int num4 = (num % 100000)%1000;
	a[0] = num1;
	a[1] = num2;
	a[2] = num3;
	a[3] = num4;
}


int main(){
	int a[4] = {0,0,0,0};
	int i;
	for (i = 100000000;i<999999999;i++){
		get_nums(i,a);
		//去掉不必要的情况 
		if (all_one(a) == 0){
			continue;
		}
		//判断是否符合要求 
		if(a[0] * a[1] == a[2] * a[3]){
			printf("%d * %d = %d * %d\n",a[0],a[1],a[2],a[3]);
		}
	}
	return 0;
} 

最后输出结果

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值