我是靠谱客的博主 怕孤独硬币,最近开发中收集的这篇文章主要介绍【C++实现】安卓手机锁屏手势密码种数【模拟+递归搜索】,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

【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 2sqrt2 22

当下一状态手势点和当前状态点的距离 dis = 2 2 2sqrt2 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

最后

以上就是怕孤独硬币为你收集整理的【C++实现】安卓手机锁屏手势密码种数【模拟+递归搜索】的全部内容,希望文章能够帮你解决【C++实现】安卓手机锁屏手势密码种数【模拟+递归搜索】所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部