【C++实现】安卓手机锁屏手势密码种数【模拟+递归搜索】

23 篇文章 0 订阅

【C++实现】安卓手机锁屏手势密码种数【模拟+递归搜索】

题目:
计算出安卓手机上的解锁屏幕手势密码的种类数目
(正确答案:389112种)

需要考虑的实际情况:
1.用户最少划4个点作为手势密码
2.不考虑用户的误触,两点之间可以按“日”轨迹滑动
3.两点之间如果存在第三个点,这个第三个点一定被手势激活

思路:
主要利用模拟和递归搜索。
正确的规则如下:

根据规则编写递归代码:

参数说明:
	n: 代表手势点的个数
	count: 代表在n个手势点的情况下,合法的组合种数
	x,y: 代表当前状态下的手势点划到的位置
递归终止条件:
	当n==1时,说明手势点已经通过某条合法的路径划了n个点
		count++
递归执行逻辑:
	1.遍历所有手势点,找到没有访问过的手势点,
	进一步判断该手势点是否满足上述的正确规则;
		2.如果满足上述正确规则,则标记访问该手势点,递归,回溯

关于判断两点之间是否满足正确规则的方法:
核心:利用两点距离
通过分析可以发现,两点的距离从小到大包括:
1 1 1 2 \sqrt2 2

所以当下一状态手势点和当前状态点的距离 dis ≤ 2 \sqrt2 2 时,说明两点之间一定不会存在第三点。可直接进入递归。

2 2 2

当下一状态手势点和当前状态点的距离 dis = 2 时,说明两点之间一定会存在第三点,此时需要判断中间点是否访问过,如果访问过说明合法。方可进入递归。

5 \sqrt5 5

所以当下一状态手势点和当前状态点的距离 dis = 5 \sqrt5 5 时,说明两点之间一定不会存在第三点。可直接进入递归。

2 2 2\sqrt2 22

当下一状态手势点和当前状态点的距离 dis = 2 2 2\sqrt2 22 时,说明两点之间一定会存在第三点,此时需要判断中间点是否访问过,如果访问过说明合法。方可进入递归。

代码:

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

bool visited[3][3];//代表当前某点是否已经访问过

//n:代表手势点的个数
//count:代表合法的组合种数
//x,y:代表当前状态下的点位置
void dfs(int n, int& count, int x, int y) {
	if (n == 1) {
		count++;
		return;
	}
	for (int i = 0; i <=2 ; i++) {
		for (int j = 0; j <= 2; j++) {
			if (!visited[i][j]) {
				int a_square = (i - x)*(i - x);
				int b_square = (j - y)*(j - y);
				double dis = sqrt(a_square + b_square);
				//如果走没有访问过的相邻的点,说明合法
				if (dis <= sqrt(2)) {
					::visited[i][j] = true;
					dfs(n - 1, count, i, j);
					::visited[i][j] = false;
				}
				//如果跨一个点走横竖线,并且中间的节点是访问过的,说明合法
				else if (abs(dis - 2) <= 0.00001 && visited[(i+x)/2][(j+y)/2]) {
					::visited[i][j] = true;
					dfs(n - 1, count, i, j);
					::visited[i][j] = false;
				}
				//如果走没有访问过的日字,说明合法
				else if (abs(dis - sqrt(5)) <= 0.00001) {
					::visited[i][j] = true;
					dfs(n - 1, count, i, j);
					::visited[i][j] = false;
				}
				//如果跨一个点走斜线(如左上到右下),并且中间的节点是访问过的,说明合法
				else if (abs(dis - 2 * sqrt(2)) <= 0.00001&&visited[(i + x) / 2][(j + y) / 2]) {
					::visited[i][j] = true;
					dfs(n - 1, count, i, j);
					::visited[i][j] = false;
				}
			}
		}
	}
}


int main() {
	int sum = 0;
	for (int n = 4; n <= 9; n++) {
		int count = 0;
		for (int x = 0; x <= 2; x++) {
			for (int y = 0; y <= 2; y++) {
				//初始化第一个落指的手势点
				memset(visited, 0, sizeof(visited));
				visited[x][y] = true;
				dfs(n, count, x, y);
			}
		}
		sum += count;
		cout << "手势点 = " << n << "有" << count << "种情况。"<<endl;
	}
	cout <<"所以一共有"<< sum <<"种情况。"<< endl;
	system("pause");
	return 0;
}

运行结果:

欢迎大佬们批评指正!一同交流分享更好的思路!


PS:欢迎关注公众号~
不间断分享大厂算法题解、实习面经、学习资料等。
在这里插入图片描述文末防伪码:2020214053

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值