蓝桥杯第7届javaA组决赛第二题

蓝桥杯第7届javaA组决赛第二题

题目


凑平方数

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

再比如:
1098524736
1, 25, 6390784
0, 4, 289, 15376
等等...

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

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

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


思路:

这道题从结果上来推,先把10位以内所有的平方数算出来要用到大整数,否则会溢出,然后对这600多个数

进行全排列,并且在排列过程中进行减支
减支1:记个分组组合在一起的字符串的字符个数不能超过10个
减支2:剩下的可用长度比当前选择字符串长度还小后面就不用看了,因为我们生成平方数从小到大生成的
后面的数肯定比当前的大(这个减支不必须只是会大大降低时间)
减支3:当前选的数不能和前面已经选的字符串有相同字符

程序设计思路:

首先用一个ArrayList<BigInteger> 数组来保存所有10为以内的平方数,然后接着用一个boolen[] select数组
保存ArrayList<BigInteger> digitList中每一个数据是否被遍历过的状态遍历过则用true表示,没遍历过则用false
表示,
然后要检查当前字符串是否有相同数字,基本思想是,通过使用集合查重,因为集合中每一个元素都不相同
,把字符串当成一个set<Character>集合通过把字符串中的字符一个一传进集合中,如果集合的长度和字符串
的长度相同,没有重复,返回ture,否则字符串中有字符重复,返回false
接着用一个Set<Set<String>>集合来保存满足题意的所有分组,同时因为不考虑小组内数据的先后顺序
所以也可以使用集合来查重
再之后就是dfs深度遍历采用递归的方法,首先适合本题的dfs()函数需要三个参数int len,String figure,Set<String> figureset
每个参数的作用,第一个参数len用来表示分组中剩余的可添加字符串的长度,
第二个参数figure用来判断添加新字符串后分组是否有重复的字符
第三个参数figureset用来保存遍历到当前字符串后分组的集合
dfs()函数中的步骤,首先要判断len<0是return,否则判断len=0是说明分组已完成,添加到结果集中
return
然后进行一个for循环对于ArrayList<BigInteger> 中的每一个数开头的所有可以组成的分组,对for循环下首先是大判断
判断,判断该数是否被遍历过,没有遍历过将select[i]置为true然后将digitList[i]转化为字符串,判断 字符串的长度
是否大于剩余长度,若大于剩余长度则则不能将次平方数加入到集合中,再次将select[i]置为false跳出循环break
然后判断新加入的平房数和前面的数字是否有重复,若是没有重复则该字符串可以加入到该分组中,新建一个HashSet<Strign>
集合,然后将原先的figureset加入到集合中,然后再加入temp,递归深度遍历dfs(len-temp.length(),figure+temp,tempset)
最后就是写主函数,ArrayList<BigInteger> new对象,然后由小到大生成平方数使用一个while(true)循环,
初始的dfs(10,"",new HashSet<String>())
基本到此为止就是写代码的全部过程,还是比较不容易想得到的

接下来送上代码

package SevenProvience.test2;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

public class SelPow {
	//声明一个数组链表用来存储所有的从小到大的平方数,要用
	//大数类型,否则会溢出
	static ArrayList<BigInteger> digitlist;
	
	//对于数组中每一个元素都要标记状态,标记是否被遍历过
	public static boolean[] select;
	
	//判断当前字符串是否是否存在相同数字
	//此处判断字符串是否相同是利用集合的特性,集合中元素都不相同
	public static boolean checkDup(String digitStr){
		int len=digitStr.length();
		Set<Character> set=new HashSet<>();
		for(int i=0;i<len;i++){
			//charAt(intdex i)找出字符串中第i个字符
			set.add(digitStr.charAt(i));
		}
		//判断集合的size是否和字符串的长度相同
		//若相同说明没有重复
		if(set.size()==len){
			return true;
		}else{
			return false;
		}
	}
	//用一个集合来保存所有的分组,因为分组里面是字符串,
	//所以集合中嵌套集合
	public static Set<Set<String>> result=new HashSet<>();
	
	//进行深度遍历找出所有符合题目的分组并将分组放进result中
	public static void dfs(int len,String figure,Set<String> figureset){
		if(len<0){
			return;
		}
		//判断剩余可添加的字符串长度是是否为0
		//若为0说明分组已完成
		if(len==0){
			result.add(figureset);
			return;
		}
		//使用for循环对figure中每一个数开头的情况下所有满足题意的分组
		for(int i=0;i<select.length;i++){
			//对于还没有遍历的平方数将select[i]置为false
			if(!select[i]){
				select[i]=true;
				String temp=digitlist.get(i).toString();
				//因为最先所有的平方数最先都是从小到大生成的,后面的数肯定比当前的数
				//当前要长,因此后面的数就不用看了
				if(len<temp.length()){
					select[i]=false;
					break;
				}
				//检查加入新平方数后是否存在重复
				if(checkDup(figure+temp)){
					HashSet<String> tempSet=new HashSet<>();
					tempSet.addAll(figureset);
					tempSet.add(temp);
					//递归遍历
					dfs(len-temp.length(),figure+temp,tempSet);
				}
				//因为对于循环的下一个dfs遍历还得用select[]数组所以要将select[i]
				//置为false
				select[i]=false;
			}
			
		}
		
	}
	
	public static void main(String[] args) {
		int i = 0;
		digitlist = new ArrayList<>();
		//由小到大生成平方数
		while (true) {
			BigInteger temp = BigInteger.valueOf(i++).pow(2);
			if (temp.toString().length() <= 10) {
				if (checkDup(temp.toString())){
					
					digitlist.add(temp);
					System.out.println(temp.toString());
					}
				
			} else{
				break;
			}
		}
		select=new boolean[digitlist.size()];
		
		dfs(10,"",new HashSet<String>());
		//输出最终计算出的结果数目
		System.out.println(result.size());
	}

}






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值