九宫幻方--

题目描述


    小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将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

分析:由于题目的九宫幻方的情况很少,所以我们可以预先求出来然后再去判断即可,那么一共有多少种情况呢?

    我们可以这样考虑,将原来的矩阵经过旋转得到4种情况,我们只看一个数,比如是4,有4个位置,4的位置确定以后2的位置 自然也确定了,对称的话只需要将2旋转一下即可。那么一共4*2 = 8种情况。看代码:

import java.util.*;
public class Main {
    static Scanner in = new Scanner(System.in);
    static int[][] a = new int[3][3];
    static int cnt,ans;
    static String[] ss = {"492357816","834159672","618753294","276951438",
    		              "438951276","294753618","672159834","816357492"};
	public static void main(String[] args) {
		String s = "";
		for(int i = 0;i < 3;i++)
			for(int j = 0;j < 3;j++) {
				a[i][j] = in.nextInt();
				s+=a[i][j];
		 }
		boolean f = false;
		for(int i = 0;i < 8;i++) {
			 f = false;
			for(int j = 0;j < 8;j++) {
			 if((ss[i].charAt(j)==s.charAt(j))||s.charAt(j)=='0')
				  continue;		
			 if(ss[i].charAt(j)!=s.charAt(j)) {
				 f = true;break;
			 }
	      }
	      if(!f) {
	    	  cnt++;
	    	  ans = i;
	     }	      
	  }
	 if(cnt==1) {
		 for(int i = 0;i < 9;i+=3)
			for(int j = i;j < i + 3;j++) {
		     if(j!=i+2)
			    System.out.print(ss[ans].charAt(j)+" ");
		     else
		    	 System.out.println(ss[ans].charAt(j)); 
		   }
	 }else 
		 System.out.println("Too Many");
	}
}

思考:其实可以用用暴搜直接判断即可,看代码:

import java.util.*;

public class Main {
	static Scanner in = new Scanner(System.in); 
    static int[][] a = new int[3][3];
    static int[] b = new int[10];
    static int[] c = new int[10];
    static int maxn = 9,ans = 0;
    static void dfs(int sp) {//全排列
    	if(sp>=maxn) {
    		boolean f = true ;
    		for(int i = 0;i < 3;i++)  
	            for(int j = 0;j < 3;j++) {  
	                 if(a[i][j]!=0&&b[i*3+j]!=a[i][j])//对应位置不正确 
	                	 f = false;
	         }
    		if(f) {//判断每一行和是否相同
    			for(int i = 0;i < 3;i++) {  
    				int sum = 0;
    	            for(int j = 0;j < 3;j++) 
    	                 sum+=b[i*3+j];
    	            if(sum!=15) {
    	            	f = false;break;
    	             }
    	         }
    		}
    		if(f) {//判断每一列和是否相同
    			for(int j = 0;j < 3;j++) {  
    				int sum = 0;
    	            for(int i = 0;i < 3;i++) 
    	                 sum+=b[i*3+j];
    	            if(sum!=15) {
    	            	f = false;break;
    	             }
    	         }
    		}
    		if(b[0]+b[4]+b[8]!=15||b[2]+b[4]+b[6]!=15)//对角线
    			f = false;
    		if(f) {
    			ans++;
    			for(int i = 0;i < maxn;i++)
    				c[i] = b[i];
    			return;
    		}
    	}
    	for(int i = sp;i <= maxn;i++) {//交换思想,可以看我写过的全排列的文章
        int t = b[sp];b[sp] = b[i];b[i] = t;
    	  dfs(sp+1);
    	  t = b[sp];b[sp] = b[i];b[i] = t;
    	}
    }
	public static void main(String[] args) {		
	    for(int i = 1;i <= maxn;i++)
			 b[i] = i;
	        for(int i = 0;i < 3;i++)  
	            for(int j = 0;j < 3;j++) {  
	                a[i][j] = in.nextInt();  	                 
	         } 
	    long s = System.currentTimeMillis();    
	    dfs(0);
	    if(ans>1)
	    	System.out.println("Too Many");
	    else {
	    	 for(int i = 0;i < 3;i++)  
		         for(int j = 0;j < 3;j++) { //注意控制格式输出
		             if(j!=2)
		            	 System.out.print(c[i*3+j]+" ");
		             else
		            	 System.out.println(c[i*3+j]);
		        }
	    }
	    long e = System.currentTimeMillis();
	    System.out.println(e-s);//计算程序运行时间(毫秒)
	}

}
但是时间复杂度的话肯定是要高很多了,可以对比一下程序运行时间。

猜你喜欢

转载自blog.csdn.net/JingleLiA/article/details/79725118