ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【每日蓝桥】41、一六年省赛Java组真题“方格填数“四平方和”

2021-03-23 18:59:19  阅读:224  来源: 互联网

标签:组真题 Java int Arr 平方和 蓝桥 循环 static ansArr


你好呀,我是灰小猿,一个超会写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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有