之前在学校的一个社团招募大一新生时,给出了这个题目:
用程序编写完成九宫格图案解锁总共能绘出多少种图案
需要满足的要求有:
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