蓝桥杯-方格填数

7 篇文章 0 订阅

方格填数

如下的10个格子
+–+–+–+
| | | |
+–+–+–+–+
| | | | |
+–+–+–+–+
| | | |
+–+–+–+

(如果显示有问题,也可以参看【图1.jpg】)

填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)

一共有多少种可能的填数方案?

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

一开始直接用dfs八个方向进行搜索,结果很大,也不知道问题在哪里
最后直接一个方格一个方格的填,就出现了答案
先说一下思路吧, 对于每一个0-9的数进行标记,对于每一个坐标点进行填数
对填写的数进行判断如果可以直接填写,然后进行下一个dfs
如果不可以进行寻找合适的数字,找不到直接回溯到上一个dfs

答案:1580
java代码实现:
朋友做的代码效率比我高出N倍…:

    package com.tjrac_java_2;

public class QuanPaiLie {
    static int all=0;
    static int[] num=
    {
    -2,-2,-2,-2,-2,-2,
    -2,-2,10,10,10,-2,
    -2,10,10,10,10,-2,
    -2,10,10,10,-2,-2,
    -2,-2,-2,-2,-2,-2,
    };
    static int []useful={8,9,10,13,14,15,16,19,20,21};
    static int check(int i)//该位置方格的上,左,左上,右上
    {   
        if(num[i]==num[i-1]-1||num[i]==num[i-1]+1)
            return 0;
        else if(num[i]==num[i-6]-1||num[i]==num[i-6]+1)
            return 0;
        else if(num[i]==num[i-7]-1||num[i]==num[i-7]+1)
            return 0;
        else if(num[i]==num[i-5]-1||num[i]==num[i-5]+1)
            return 0;
        else
            return 1;
    }
    static int check_same(int i)//判断该方格中的数字是否被用过
    {
        for(int j=0;j<i;++j)
            if(num[useful[j]]==num[useful[i]])
                return 0;
        return 1;
    }
    static void func(int round)
    {
        if(round>9)//如果round>9表示已经给所有方格添加数字
        {   
            ++all;
            return ;
        }
        else
            for(int i=0;i<=9;++i)
                {
                    num[useful[round]]=i;//数字添加到方格中
                    if(check_same(round)==1&&check(useful[round])==1)//判断该方格数字是否已经用过,以及该填充的方格数字满足相邻不为1
                        func(round+1);//递归遍历下一个方格
                }
    }
    public static void main(String[] args) {
        func(0);
        System.out.println(all);
    }
}

自己代码(58000ms,呵呵。。。):

package com.tjrac_java_2;

public class SumCount {
    //考虑到边界问题把数组行列扩大两位
    static int count=0, sum = 0;//count表示已经填充数的字格数。sum表示最后输出结果
    static int[][] go = {{0,1},{1,0},{0,-1},{1,-1},{-1,0},{-1,1},{-1,-1},{1,1}};//右、下、左、左下、上、右上、左上、右下
    static int[][] newGo={{-1,0},{1,0},{0,-1},{0,1}};
    static int[] num = new int[10];//用来判断该数字是否用过,用过为1 否则为0
    static int[] road = new int[11];
    static int flag=0;
    static long start , end;
    public static void main(String[] args) {
        start = System.currentTimeMillis();
        int [][] a = new int [5][6];
        for (int i = 0; i < 10; i++) {
            num[i]=0;
        }
        for(int i=0;i<5;i++){
            for(int j=0;j<6;j++){
                a[i][j]=11;//表示可以访问,之所以为11因为方便判断不相邻
            }
        }
        for(int i=0;i<10;i++){
            a[1][2]=i;//控制第一个方格的值
            num[i]=1;//标记i不能再用了
            count++;
            flag=i;
            //road[i]=12;//路径
            DFS(a,1,2);
            a[1][2]=11;
            num[i]=0;
            count--;
        }
        System.out.println("总次数:"+sum);
        System.out.println("用时:"+(System.currentTimeMillis()-start));
//      for (int is : road) {
//          System.out.println(is);
//      }
    }

    private static void DFS(int[][] a, int x, int y) {
        //递归出口
        //表示10个数字填充完毕
        System.out.println("ok");
        if(count == 10 ){
            sum++;
            return ;
        }else{
            //for(int i = 0; i < 8; i ++){
                for(int i = 0; i < 4; i++){
                    //往相邻方格填数字
                    int xx = x + go[i][0];
                    int yy = y + go[i][1];
                    //判断边界,是否已经填充了数字,满足相邻不为1
                    if((xx==1&&yy==1) || (xx==3&&yy==4))continue;//因为11和44不能访问
                    if(xx >= 1 && xx <= 3 && yy >= 1 && yy <= 4 && a[xx][yy] ==11 ){
                        //往该方格中放数字
                        System.out.println("上个方格:"+"x:"+x+"->>y:"+y);
                        System.out.println("现在方格:"+"xx: "+xx+"  yy: "+yy);
                        for( int k = 0; k < 10; k++){
                            //判断该数字是否被用过,并且数字不相邻
                            if(num[k] == 0 && Math.abs(k-a[xx][yy+1])!=1 && Math.abs(k-a[xx+1][yy])!=1 && Math.abs(k-a[xx][yy-1])!=1 && Math.abs(k-a[xx+1][yy-1])!=1 &&Math.abs(k-a[xx-1][yy])!=1&& Math.abs(k-a[xx-1][yy+1])!=1 &&Math.abs(k-a[xx-1][yy-1])!=1&& Math.abs(k-a[xx+1][yy+1])!=1){
                                a[xx][yy] = k;System.out.println("填入数字:"+"xx: "+xx+"   "+yy+"   数字:"+k+"右边:"+a[xx][yy-1]);
                                num[k]=1;
                                count++;
                                //road[count]=xx*10+yy;
                                DFS(a,xx,yy);
                                a[xx][yy] = 11;
                                num[k]=0;
                                count--;System.out.println("填入的方格总数:"+count);
                /*              if(count<0){
                                    return;
                                }*/

                            }
                        }
                    }
                }
            //}
        }


    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
方格填数是一种经典的数学游戏,通过填写数字使得每行、每列和每个小方格内的数字均不重复。在Python中可以通过回溯算法实现方格填数游戏的求解。下面是一个简单的实现示例: ```python # 方格填数游戏求解 # 定义游戏棋盘 board = [[0 for i in range(9)] for j in range(9)] # 定义判断是否可填数字的函数 def is_valid(row, col, num): # 判断行和列是否重复 for i in range(9): if board[row][i] == num or board[i][col] == num: return False # 判断小方格是否重复 start_row = (row // 3) * 3 start_col = (col // 3) * 3 for i in range(start_row, start_row + 3): for j in range(start_col, start_col + 3): if board[i][j] == num: return False return True # 定义回溯函数 def backtrack(row, col): # 判断是否填满 if row == 9: return True # 计算下一个位置 next_row = row if col < 8 else row + 1 next_col = (col + 1) % 9 # 如果已经填过,则跳过 if board[row][col] != 0: return backtrack(next_row, next_col) # 尝试填数字 for num in range(1, 10): if is_valid(row, col, num): board[row][col] = num if backtrack(next_row, next_col): return True board[row][col] = 0 return False # 求解方格填数游戏 backtrack(0, 0) # 输出结果 for row in board: print(row) ``` 可以看到,该算法通过递归实现对棋盘的深度优先搜索,并在每个格子中尝试填入数字,如果符合要求就继续搜索下一步。如果搜索到最后,即填满了整个棋盘,则返回True,否则返回False。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值