DFS----手机屏幕解锁模式

现有一个 3x3 规格的 Android 智能手机锁屏程序和两个正整数 m 和 n ,请计算出使用最少m 个键和最多 n个键可以解锁该屏幕的所有有效模式总数。
其中有效模式是指:
1、每个模式必须连接至少m个键和最多n个键;
2、所有的键都必须是不同的;
3、如果在模式中连接两个连续键的行通过任何其他键,则其他键必须在模式中选择,不允许跳过非选择键(如图);
4、顺序相关,单键有效(这里可能跟部分手机不同)。
在这里插入图片描述

输入:m,n
代表允许解锁的最少m个键和最多n个键
输出:
满足m和n个键数的所有有效模式的总数

输入例子1:
1,2
输出例子1:
65
例子说明1:
输入m=1,n=2,表示最少1个键,最多2个键,符合要求的键数是1个键和2个键,其中1个键的有效模式有9种,两个键的有效模式有56种,所以最终有效模式总数是9+56=65种,最终输出65。

class Solution {
public:
    /**
     * 实现方案
     * @param m int整型 最少m个键
     * @param n int整型 最多n个键
     * @return int整型
     */

    void move(vector<vector<int> >& board, int i, int j, int k, int m, int n, int& ans){
        // 如果已经走过的点数大于等于m,则是有效路径,ans++
        if(k >= m) ans ++;
        // 如果已经走过的点数等于n,则不需要继续探索,故返回
        if(k == n) return;
        // 如果已经走过的点数小于n,则还可以继续探索
        for(int dx=-2; dx<=2; dx++){
            for(int dy=-2; dy<=2; dy++){
            	// i+dx>=0 && i+dx<=2 && j+dy>=0 && j+dy<=2是3x3格子的边界条件
            	// board[i+dx][j+dy]==0则表明该位置未曾经过
                if(i+dx>=0 && i+dx<=2 && j+dy>=0 && j+dy<=2 && board[i+dx][j+dy]==0){
                    // 如果两点之间没有第三个点(条件:dx%2 || dy%2),则无需判断是否经过“已经过”的点
                    // 如果两点之间有第三个点,则需要判断这个点是否是已经走过的点		
                    // dx%2 == 0则表示横跨2步,dy%2 == 0 表示竖跨2步
                    // 而当dx%2 || dy%2成立时,表明横向跨1步,或者纵向跨1步,一旦只跨1步则不存在中间点了,可以画图结合理解
                    // (!(dx%2) && !(dy%2) && board[i+dx/2][j+dy/2]==1) 成立时,表明横跨2步,纵跨2步,并且横跨1纵跨1的点(即中点)已经走过(因为1表示走过)
                    if(dx%2 || dy%2 || (!(dx%2) && !(dy%2) && board[i+dx/2][j+dy/2]==1)){
                    
                        board[i+dx][j+dy] = 1;
                        move(board, i+dx, j+dy, k+1, m, n, ans);
                        board[i+dx][j+dy] = 0;
                    }
                }
            }
        }
          
        return;
    }
      
    int solution(int m, int n) {
        // write code here
        vector<vector<int> > board(3, vector<int>(3, 0));
        int ans = 0;
        // 如果n等于0,则直接返回0
        if(n == 0) return ans;
         
        // 选择棋盘上任意一点作为起点
        for(int i=0; i<3; i++){
            for(int j=0; j<3; j++){
                board[i][j] = 1;
                move(board, i, j, 1, m, n, ans);
                board[i][j] = 0;
            }
        }
        return ans;
    }
};

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值