zoukankan      html  css  js  c++  java
  • 蓝桥真题----拉丁方块填数字

    /*  方块填数

     “数独”是当下炙手可热的智力游戏。一般认为它的起源是“拉丁方块”,是大数学家欧拉于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数组,表示颜色位置。

     

     

     

     

     

  • 相关阅读:
    [BJOI2019] 光线
    [BJOI2019]奥术神杖
    [HNOI2014]江南乐
    [SDOI2018]荣誉称号
    [APIO2015]雅加达的摩天楼
    [TJOI2015]线性代数
    【CF163E 】e-Government
    【CF917D】Stranger Trees
    网络流(四)dinic算法
    网络流(三)最大流最小割定理
  • 原文地址:https://www.cnblogs.com/ls-pankong/p/10457081.html
Copyright © 2011-2022 走看看