编程语言
首页 > 编程语言> > 【每日蓝桥】41、一六年省赛Java组真题“方格填数“四平方和”

【每日蓝桥】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