之前在学校的一个社团招募大一新生时,给出了这个题目:
用程序编写完成九宫格图案解锁总共能绘出多少种图案
需要满足的要求有:
1.至少经过四个点;2.不能重复经过同一个点;
3.路径上的中间点不能跳过(如从1到3一定会经过2);
4.如果中间的点是之前已经用过的,那么这个点就可以被跳过(如213,因为2已经被用过,1就可以越过2与3连接,132是不允许的)。
当时就在想,出这道题的社团负责人脑子是不是瓦特掉了,给大一的小孩子们刚开始就下这么猛的料。
问题跟我们的生活息息相关,毕竟现在大家都用的智能手机。看到题目后立马想到了用递归算法来完成此问题。后来,抽空闲时间用C语言编写出了此程序。
代码见如下图所示:
#include <stdio.h> #define M 3 int zhen[5][5]; int count=0; void init(int a[5][5]) //初始化数组 { int i,j,num=1; for(i=0;i<M;i++) for(j=0;j<M;j++) { a[i][j]=0; } } int decide(int a[5][5],int m,int n,int x,int y) //判断当前手势顺序是否是一个合法手势 { int max,min; int flag1=m-x; int flag2=(n-y)*(-1); if(m==-1&&n==-1) return 1; if((m==x)&&(n!=y)) { if(n>y) { max=n; min=y; }else { max=y; min=n; } for(min+=1;min<max;min++) { if(a[m][min]==0) return 0; } return 1; } if((m!=x)&&(n==y)) { if(m>x) { max=m; min=x; }else { max=x; min=m; } for(min+=1;min<max;min++) { if(a[min][n]==0) return 0; } return 1; } if(m==n&&x==y) { if(m>x) { max=m; min=x; } else { max=x; min=m; } for(min+=1;min<max;min++) { if(a[min][min]==0) return 0; } return 1; } if(flag1==flag2) { if(m>x) { for(m-=1,n+=1;(m>x)&&(n<y);m--,n++) if(a[m][n]==0) return 0; }else { for(m+=1,n-=1;(m<x)&(n>y);m++,n--) if(a[m][n]==0) return 0; } return 1; } return 1; } void deal(int a[5][5],int level,int m,int n) { int i,j; int flag; if((m<M)&&(n<M)) { for(i=0;i<M;i++) { for(j=0;j<M;j++) { if(a[i][j]!=1) { flag=decide(a,m,n,i,j); if(flag!=0) { a[i][j]=1; level+=1; if(level>=4) { count++; } deal(a,level,i,j); a[i][j]=0; level--; } } } } } } int main() { int i,j; init(zhen); deal(zhen,0,-1,-1); printf("%d\n",count); return 0; }
第一个函数init为数组初始化函数;第二个函数decide判断当前手势顺序是否符合要求;第三个函数deal为递归函数。程序结构并不复杂,不做过多的论述。
程序中宏M的取值为3,代表当前计算的是三宫格。宏M的取值可以改为不同的值,代表计算不的格数。但同时程序运行的时间开销会大大增加。笔者在完成此程序时,并没有太考虑程序的时间开销方面的问题。
程序算法采用了递归算法,思想上使用了穷举的思想。
最后运行结果为:389112。哈哈,证明我们采用九宫格手势做手机开机解锁在理论上还是蛮安全的。
程序源码下载地址:https://github.com/XiaoYaoNet/ThreeTable