蓝桥杯 历届试题 九宫幻方

问题描述

  小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将1~9不重复的填入一个3*3的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。

三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:“二四为肩,六八为足,左三右七,戴九履一,五居其中”,通过这样的一句口诀就能够非常完美的构造出一个九宫格来。

4 9 2
3 5 7
8 1 6

  有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。

  而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序。


输入格式

  输入仅包含单组测试数据。
  每组测试数据为一个3*3的矩阵,其中为0的部分表示被小明抹去的部分。
  对于100%的数据,满足给出的矩阵至少能还原出一组可行的三阶幻方。


输出格式

  如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出“Too Many”(不包含引号)。


样例输入

0 7 2
0 5 0
0 3 0


样例输出

6 7 2
1 5 9
8 3 4


解题思路:

  由于数据量不大,所以直接深搜回溯就行,千万不要忘记回溯;其实这题的测试数据是不考虑有多种解的情况,也就是说不考虑多种解的情况也能通过所有测试数据。不过为了符合题目要求下面的代码考虑了多种解的情况。

解题代码:

import java.util.Scanner;

public class 九宫幻方 {
	static int count = 0;
	static int[] arr = new int[9];  //存储九宫格的九个数字
	static int[] res = new int[9];   //记录唯一的结果
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		for(int i=0; i<9; i++){
			arr[i] = scanner.nextInt();
		}
		dfs(0);            
		int c =0;
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++){
				System.out.print(res[c++] + " ");
			}
			System.out.println();
		}
	}

	//深搜,依次遍历每一个格子
	private static void dfs(int index) {
		if(index ==9){  //递归出口
			if(isOk()){  //检查当前的九宫格是否符合条件
				if(count==0){
					//res = arr;  不能用这样的赋值方式,因为res和arr是对象的引用,
					//如果这样赋值,arr之后改变,res也会改变
					for(int i=0; i<arr.length; i++){
						res[i] = arr[i];
					}
					count++;
				}else{
					System.out.println("Too Many");
					System.exit(0);
				}
			}
			return ;
		}
		if(arr[index] == 0){
			for(int i=1; i<=9; i++){
				if(check(index, i)){ //如果能放
					arr[index] = i;
					dfs(index+1); 
					arr[index] = 0;   //回溯
				}
			}
		}else{
			dfs(index+1);
			return ;
		}
	}

	//检查九宫格是否符合条件
	private static boolean isOk() {
		int[][] a = new int[3][3];
		int c = 0;
		for(int i=0; i<3; i++){
			for(int j=0; j<3; j++){
				a[i][j] = arr[c++];
			}
		}
		int sum = a[0][0] + a[0][1] + a[0][2];  //第一行的和
		if(a[1][0] + a[1][1] + a[1][2] != sum)
			return false;
		if(a[2][0] + a[2][1] + a[2][2] != sum)
			return false;
		if(a[0][0] + a[1][0] + a[2][0] != sum)  //计算第一列
			return false;
		if(a[0][1] + a[1][1] + a[2][1] != sum)  
			return false;
		if(a[0][2] + a[1][2] + a[2][2] != sum)  
			return false;
		if(a[0][0] + a[1][1] + a[2][2] != sum)  //计算主对角线
			return false;
		if(a[0][2] + a[1][1] + a[2][0] != sum)  //计算斜对角线
			return false;
		return true;
	}

	//检查x是否已经放过
	private static boolean check(int index, int x) {
		for(int i=0; i<arr.length; i++){ //是要与之前的数进行对比,不是所有的数进行对比
			if(arr[i] == x){
				return false;
			}
		}
		return true;
	}
}

注意:数组之间的赋值不要采用res = arr 的方式。这是引用的赋值,两个引用会指向同一个对象。

测试结果:

在这里插入图片描述

你可能感兴趣的:(#,蓝桥杯官网训练题,#,蓝桥杯历年真题)