第七届蓝桥杯(国赛)--凑平方数

题目描述:

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

比如:0, 36, 5948721

再比如:

1098524736

1, 25, 6390784

0, 4, 289, 15376

等等...

注意,0可以作为独立的数字,但不能作为多位数字的开始。

分组时,必须用完所有的数字,不能重复,不能遗漏。

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

注意:需要提交的是一个整数,不要填写多余内容。

/*
0 1 4 9 16 25 36 49 64 81 100(重复) 121(重复)
首先要记录每一个无重复数的平方数的二进制
因为只平移个位数上的值
如0用0000000001表示 1用0000000010表示 4用00000010000表示 9用1000000000 16用0001000010
number[0] = 1
number[1] = 2
number[2] = 16//10000即4
number[3] = 512//10000000000 即9
*/ 
#include <iostream>
using namespace std;
#define MAX 100000
int repeat(long long square)
{
	int recording = 0; //记录二进制转十进制的数值
	do
	{
		int bit = square % 10;
		if(((1 << bit) & recording) != 0)//判断是否有重复个数 ,不等于0则证明数值出现过 
		{
			return 0;
		}
		recording = recording | (1 << bit);//将个位数上的二进制记录到0000000000里面
	}while((square /= 10) != 0);
	return recording;
}
void q_number(int number[], int &num)
{
	num = 0;
	for(int i = 0; i < MAX; i++)
	{
		if(repeat((long long)i*i))//传数值的平方的同时判断数值是否有重复数,平方数可能超过int类型最大值,所以要转换成long long 类型 
		{
			number[num++] = repeat((long long)i*i);
            //记录每个个位数平移之个位数数值之后的数转十进制的数值(方便判断是否有重复数值) 
		}
	}
	return;
}

int q_count(int n, int number[],int index)//n表示已有数值 
{
	int count = 0;//记录组合的个数
	while(number[index] != -1)
	{	
		if((n & number[index]) == 0)//判断新的数值与数组里面的数值是否相等
		{
			if((n | number[index]) == 1023)
            //判断二进制时是否等于1111111111,即判断十进制数是否等于1023
			{
				count++;
			}
			else
			{
				count += q_count((n | number[index]), number, index+1);
                //通过递归的方法来遍历数组进行组合
			}
			
		}
		index++;
	} 
	return count;
}
int main()
{
	int number[MAX];//因为是10位数里面的平方所以可以用int存储
	int num = 0;//记录number的下标
	q_number(number,num);//求平方数的二进制(用十进制来存)
	number[num] = -1;//用来记录末尾值,以便最后遍历时不用传递num个数的参数
	//cout << "num = " << num <<endl;
	cout <<  q_count(0,number,0) << endl;//求组合的个数
	 
	return 0;
}

最后的答案是300,及使用完0~9且无重复数的平方数组成的组合有300个。

总结:可以通过位移个位数来判断是否有重复的数值出现,并且可以通过将一个数值的个位数移动

如16 先将 (1 << 6) & 0000000000得到 0001000000

再将(1 << 1) & 0001000000 得到0001000010 

最后将0001000010 转换为十进制得到66,即number[4] = 66;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值