【每日蓝桥】41、一六年省赛Java组真题“方格填数“四平方和”
作者:互联网
你好呀,我是灰小猿,一个超会写bug的程序猿!
欢迎大家关注我的专栏“每日蓝桥”,该专栏的主要作用是和大家分享近几年蓝桥杯省赛及决赛等真题,解析其中存在的算法思想、数据结构等内容,帮助大家学习到更多的知识和技术!
标题:四平方和
四平方和定理,又被称为拉格朗日定理。
每个正整数都可以表示为至多四个正整数的平方和,
如果把0包括进去,就正好可以表示为4个数的平方和。
比如:
5=0^2+0^2+1^2+2^2
7=1^2+1^2+1^2+2^2
(^表示乘方的意思)
对于一个给定的正整数,可能存在多种平方和的表示方法。
要求你对4个数排序,
0<=a<=b<=c<=d
并对所有的可能表示法按a,b,c,d为联合主键升序排列,最后输出第一个表示法,
程序输入一个正整数N(N<500000)
要求输出4个非负整数,按从小到大排序,中间用空格分开,
例如:输入
5则程序应该输出:
0 0 1 2
再例如,输入:
12
则程序输出:
0 2 2 2
再例如,输入:
773535
程序输出:
1 1 267 838
【资源约定】
峰值内存消耗(含虚拟机)< 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足的打印类似“请您输入...”的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句,不要使用jdk1.6及以上的版本特性
注意:主类的名称必须是Main 否则按无效代码处理。
解题思路:
本题在求解上主要使用的还是暴力枚举的方法,但是对于这道题来讲,四个for循环的嵌套在循环上是十分占用内存和CPU的,所以即使使用了循环嵌套语句,也应该对其进行合理的优化减少循环次数,所以应该清楚每一个数的取值范围,之后简化循环,
第二种方法是尽可能的减少循环的次数,所以我们可以仅仅只对前两个数进行循环,之后判断N与前两个数的平方和的差值,是否是两个数的平方和,如果是,则说明符合题目要求,因此我们需要先将两个数的平方和在map中进行存储,之后才能进行判断,当判断成功之后,这个时候输出四个数并且跳出循环即可,
下面是这两种解法的代码:
答案源码:
解法一:
public class Year2016_Bt8 { static int N; static int [] ansArr = new int[4]; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); N = scanner.nextInt(); //对答案数组进行初始化 for (int i = 0; i < 4; i++) { ansArr[i] = N; } int [] Arr = new int[4];//定义存放临时答案的数组 /** * 根据题目要求确定每一个数字的范围 * 设数字从第一个a开始,之后的数逐渐增大,所以第一个数最大应该是N除以4份之后,开平方 * */ for (int a = 0; a <= (int)Math.sqrt(N/4)+1; a++) { if (a*a>N||a>ansArr[0]) break;//如果该数的平方或该数已经大于正确答案的第一个数,则不再进行之后的循环 for (int b = a; b <= (int)Math.sqrt(N/3)+1; b++) { if(a*a+b*b>N) break; for (int c = b; c <= (int)Math.sqrt(N/2)+1; c++) { if(a*a+b*b+c*c>N) break; for (int d = c; d <= (int)Math.sqrt(N)+1; d++) { if (a*a+b*b+c*c+d*d>N) break; if (a*a+b*b+c*c+d*d==N) { Arr[0] = a; Arr[1] = b; Arr[2] = c; Arr[3] = d; check(Arr); break; } } } } } System.out.println(ansArr[0] + " " + ansArr[1] + " " + ansArr[2] + " " + ansArr[3]); } //将新得到的答案和上一个答案对比,并将较小的数组存放到答案数组中 private static void check(int[] arr) { for (int i = 0; i < arr.length; i++) { if (arr[i]<ansArr[i]) { ansArr[0] = arr[0]; ansArr[1] = arr[1]; ansArr[2] = arr[2]; ansArr[3] = arr[3]; return; } if (arr[i]>ansArr[i]) { return; } } } }
解法二:
import java.util.HashMap; import java.util.Map; import java.util.Scanner; public class Year2016_Bt8_2 { static Map<Integer, Integer> map = new HashMap<Integer, Integer>(); public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int N = scanner.nextInt(); for (int c = 0; c*c <= N/2 ; c++) { for (int d = 0; c*c+d*d<=N; d++) { //如果查找到的是空,说明map中未存储该数值 if (map.get(c*c+d*d)==null) { map.put(c*c+d*d, c);//将键值进行存储 } } } //循环遍历枚举可能的数值 for (int a = 0; a <= N/4; a++) { for (int b = 0; a*a+b*b <= N/2; b++) { //这里判断N与前两个数的平方和的差值,是否是两个数的平方和 //根据上面存储到map中的键值对,如果不等于null,则说明存在 if (map.get(N-a*a-b*b)!=null) { int c = map.get(N-a*a-b*b);//获取到c int d = (int)Math.sqrt(N-a*a-b*b-c*c);//获取到d System.out.println(a + " " + b + " " + c + " " + d); return;//跳出循环结束 } } } } }
输出样例:
其中有不足或者改进的地方,还希望小伙伴留言提出,一起学习!
感兴趣的小伙伴可以关注专栏!
灰小猿陪你一起进步!
标签:组真题,Java,int,Arr,平方和,蓝桥,循环,static,ansArr 来源: https://blog.csdn.net/weixin_44985880/article/details/115136502