蓝桥真题----拉丁方块填数字

/*  方块填数

 “数独”是当下炙手可热的智力游戏。一般认为它的起源是“拉丁方块”,是大数学家欧拉于1783年发明的。

如图[1.jpg]所示:6x6的小格被分为6个部分(图中用不同的颜色区分),每个部分含有6个小格(以下也称为分组)。

 

    开始的时候,某些小格中已经填写了字母(ABCDEF之一)。需要在所有剩下的小格中补填字母。

    全部填好后,必须满足如下约束:

    1. 所填字母只允许是A,B,C,D,E,F 中的某一个。

    2. 每行的6个小格中,所填写的字母不能重复。

    3. 每列的6个小格中,所填写的字母不能重复。

    4. 每个分组(参见图中不同颜色表示)包含的6个小格中,所填写的字母不能重复。

    为了表示上的方便,我们用下面的6阶方阵来表示图[1.jpg]对应的分组情况(组号为0~5):

000011

022013                      

221113

243333

244455

445555

    用下面的数据表示其已有字母的填写情况:

02C

03B

05A

20D

35E

53F

    很明显,第一列表示行号,第二列表示列号,第三列表示填写的字母。行号、列号都从0开始计算。

    一种可行的填写方案(此题刚好答案唯一)为:

E F C B D A

A C E D F B

D A B E C F

F B D C A E

B D F A E C

C E A F B D

    你的任务是:编写程序,对一般的拉丁方块问题求解,如果多解,要求找到所有解。

【输入、输出格式要求】

    用户首先输入6行数据,表示拉丁方块的分组情况。

    接着用户输入一个整数n (n<36), 表示接下来的数据行数

    接着输入n行数据,每行表示一个预先填写的字母。

    程序则输出所有可能的解(各个解间的顺序不重要)。

    每个解占用7行。

    即,先输出一个整数,表示该解的序号(从1开始),接着输出一个6x6的字母方阵,表示该解。

    解的字母之间用空格分开。

    如果找不到任何满足条件的解,则输出“无解”

    例如:用户输入:

000011

022013

221113

243333

244455

445555

6

02C

03B

05A

20D

35E

53F

    则程序输出:

1

E F C B D A

A C E D F B

D A B E C F

F B D C A E

B D F A E C

C E A F B D

 

   再如,用户输入:

001111

002113

022243

022443

544433

555553

7

04B

05A

13D

14C

24E

50C

51A

    则程序输出:

1

D C E F B A

E F A D C B

A B F C E D

B E D A F C

F D C B A E

C A B E D F

2

D C E F B A

E F A D C B

A D F B E C

B E C A F D

F B D C A E

C A B E D F

3

D C F E B A

A E B D C F

F D A C E B

B F E A D C

E B C F A D

C A D B F E

4

D C F E B A

B E A D C F

A D C F E B

F B E A D C

E F B C A D

C A D B F E

5

D C F E B A

E F A D C B

A B C F E D

B E D A F C

F D B C A E

C A E B D F

6

D C F E B A

E F A D C B

A B D F E C

B E C A F D

F D B C A E

C A E B D F

7

D C F E B A

E F A D C B

A D B F E C

B E C A F D

F B D C A E

C A E B D F

8

D C F E B A

F E A D C B

A D B C E F

B F E A D C

E B C F A D

C A D B F E

9

D C F E B A

F E A D C B

A F C B E D

B D E A F C

E B D C A F

C A B F D E

 */

 

注:应该开三个数组,一个记录分组情况m,一个表示字母情况zimu,一个表示6种颜色的位置情况po

 

package test3;
import java.util.*;
import java.util.Scanner;
public class Main72 {
    static class Point{
        int x;
        int y;
        public Point(int x, int y){
            this.x = x;
            this.y=y;
        }
    }
     
    public static int[][]m= new int[6][6];
    public static int[][]zimu=new int[6][6];
    public static Point[][]po = new Point[6][6];
    
    public static void init(){        //初始化
        Scanner sc = new Scanner(System.in);    
        for(int i=0;i<6;i++){
            String temp  = sc.nextLine();
            for(int j=0;j<6;j++){
                m[i][j]=temp.charAt(j)-'0';
                zimu[i][j]=-1;                //先将矩阵的每个字母赋-1,表示此位置未放字母。
            }
        }
        for(int i=0;i<6;i++){
            int index =0;                //表示0~5这六种颜色
            for(int j=0;j<6;j++){
                for(int k = 0;k<6;k++){
                    if(m[j][k]==i){
                        po[i][index++]=new Point(j,k);        //表示第i种颜色的各个点位置
                    }
                }
            }
        }
        int n = sc.nextInt();
        for(int i=0;i<n;i++){
            char[]temp  = sc.next().toCharArray();
            int x = temp[0]-'0';
            int y = temp[1]-'0';
            zimu[x][y]=temp[2]-'A';                //设置字母数组初始的字母位置
        }    
    }
    public static void DFS(int index){            //遍历这36个点
        if(index ==36){
            print();
            return;
        }
        int x = index/6;
        int y  =index%6;
        if(zimu[x][y]==-1){
            for(int i=0;i<6;i++){
                if(checkR(x,y,i)&&checkC(x,y,i)){        //检测这个点是否与行列重复和与分组的字母重复
                    zimu[x][y]=i;
                    DFS(index+1);
                    zimu[x][y]=-1;
                }
            }
            
        }else DFS(index+1);    //表示此位置已有字母,进行下一个位置
    }static int count=1;
    public static void print(){
        char[]numc=    {'A','B','C','D','E','F'};
        System.out.println(count++);
        for(int i=0;i<6;i++){
            for(int j=0;j<6;j++){
                System.out.print(numc[zimu[i][j]]+" ");
            }
        System.out.println();
        }
    }
    public static boolean checkR(int row,int col,int c){    //检测是否与分组字母重复
        int corow = m[row][col];        //corow代表c的颜色
        for(int i=0;i<6;i++){    //遍历此颜色里边的各个点
            int x = po[corow][i].x;
            int y = po[corow][i].y;
            if(zimu[x][y]==c){
                return false;
            }
        }
        return true;
    }
    public static boolean checkC(int row,int col,int c){    //检测是否行列重复
        for(int i=0;i<6;i++){    
            if(zimu[i][col]==c)
                return false;
            if(zimu[row][i]==c)
                return false;
        }
        return     true;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        init();
        DFS(0);
    }

}



//此题总结:其实考察时暴力深搜,不过条件太过于复杂,刚开始没看懂咋做,此题精华是,po数组,表示颜色位置。

 

 

 

 

 

猜你喜欢

转载自www.cnblogs.com/ls-pankong/p/10457081.html