“二十一天好习惯”第一期-12

前言;

又到了每日一更的时间了,今天给大家分享下蓝桥杯的一道基础算法题,里面包含许多基础算法知识,这里会做出总结,我们直接看题。

题目描述:

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

把 0 ~ 9 这 10 个数字,分成多个组,每个组恰好是一个平方数,这是能够办到的。

比如:

0, 36, 5948721

再比如:

1098524736
1, 25, 6390784
0, 4, 289, 15376
...

注意,0 可以作为独立的数字,但不能作为多位数字的开始。 分组时,必须用完所有的数字,不能重复,不能遗漏。

如果不计较小组内数据的先后顺序,请问有多少种不同的分组方案?

思路:

该题0-9所能组成的最大数字为:9876543210,也就是不到1e10,也就是说平方根小于1e5,可以使用暴力枚举的方法先找出1到1e5范围内所有的平方数,然后将这些平方数按照0-9每个数字只出现一次的方式进行组合,再以从小到大的顺序计数,就可得出答案。

代码实现:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1 << 10;
vector<int> nums;//存放符合条件平方数,数字的状态 
int ans;
void check(long long x){
	int status = 0;//记录数字的状态,初始时全部标位0 
	if(x==0)status=1;//标记最低位即第0位为1 
	while(x){
		//获取10进制个位上的数,1移位后与上一次的状态做与运算 
		//部位0说明个位上的数字已经被使用,则不记录,return 
	    if((status&(1<<(x%10)))!=0) 
	    return;
	    //记录数字使用情况 
	    status|=(1<<(x%10)); //标记个位对应位置为1 
	    x/=10;//消掉个位 
	}//继续处理新的个位,直到全部消掉
	//此时,原始的x每一位都被标记了status中且没用重复数字 
	nums.push_back(status);//添加到vector中 
}
void dfs(int x,int y){//从第x个合法数字往后取,当前组合状态为y 
	if(y == ( 1<< 10) - 1){//组合可行,记录答案 
		ans++; 
		return;
	}
	for (int i=x;i<nums.size();i++){//枚举先加入数字的状态 
		if((nums[i]&y==0)){//可以加入组合,去找下一个数字 
			dfs(i+1,nums[i]|y);
		}
	}
}
int main()
{ 
	//枚举算出满足题意的平方数并存储其状态 
	for(long long i;i<=100000;i++){
		check(i*i);
	}
	//用深度搜索顺序组合预处理出的平方数 
    dfs(0,0);
	cout<<ans<<endl;	
 } 

解析:

题目意思其实不难理解,但是具体实现稍微有点麻烦,这里巧妙用到了十位二进制来表示0-9中数字的出现次数。并用到了STL中的容器。先初始化为0000000000,从右到左表示0到9,若有数字出现,则在所在数字位置把0置为1。

  先看到check函数中 if((status&(1<<(x%10)))!=0)这个if语句中表示来判断这个数的个位数若在容器中相应位置为1的话则直接跳过status|=(1<<(x%10)):表示若这个数没有出现过则在vector当中相应位置进行逻辑或运算,也就是把该数位置上的0置为1。然后将这个新的平方数放入vector中

再来到dfs函数中:if(y == ( 1<< 10) - 1)ans++表示如果vector中二进制数为1111111111时则满足题意,答案数加1.  然后用递归来找下一个可以加入的组合

最后main函数先调用check函数来找平方数放入vector中,然后调用dfs函数来找符合条件的组合,最后输出答案,此题结束。

小结:

此题难点在于运用到了十位二进制来表示0-9数字的重复情况和利用逻辑或与逻辑与来处理后续的数据,还运用到了STL容器来存放数据,整体思路就是先暴力找题目范围内的平方数,然后再设计另一个函数将符合条件的组合找出,整体算法严谨又不失一丝趣味,或许这就是算法的魅力吧。今天的分享先到这里,明天准时更新。


     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值