题目描述
很多手机或平板电脑软件都可以设置手势密码,在设置了手势密码后,进入程序时,首先要输入手势密码。
手势密码最少选择4个点,最多选择9个点,理论上的密码组合总共有985824种,扣除掉其中不可能完成的组合(如一些点不允许绕过),最终的可能性是389112种。可见,手势密码加强了软件访问的安全性。
下面介绍一下手势密码的规则(如果你熟悉手势密码的规则,可略过):
1) 从某一个点出发,不间断地画线连接4-9个点,则从起点至终点构成的有序轨迹便构成一个有效的手势密码。
2) 在水平、垂直及对角方向上的3个点(假设依次为A点、B点、C点),在B点是未选点的情况下,A点是绕不过B点直接与C点相连的,如点1和点3直线连接绕不过点2。同样道理,点1和点9直线连接绕不过点5,等等。如图3所示,如果起点是1点,则手势密码必为1->2->3->6->5->4->7->8->9,而不可能是1->3->6->4->7->9。
3) 在连线不间断延展的过程中,只要还有未选的新点,就可以画线连接到该新点,而不管是否有重叠或是交叉,即经过已选点或已连线均可。例如,2->3->1->5或1->5->2->4都是允许的。
4) 在连线不间断延展的过程中,中间点是不允许经过2次的(除非是规则3说明的情况),终点虽然可以再连接到已选点,但却是无效的。例如,以1点为起点,则图4所示的手势密码跟图3所示的手势密码是一样的。
对于没研究过手势密码的同学,虽然我上面啰嗦了这么多,估计还是有疑惑的地方,干脆简单点说吧!
实际上,n个点能够构成的手势密码种数=n个点的排列总数-不可能完成的哪些排列数。
输入
有多行测试数据
每行包括2个数据:min和max,表示最少选择min个点,最多选择max个点。取值范围为4<=min<=max<=9。输入时min和max用空格隔开。
输出
与每行输入相对应,输出可以构成的手势密码总数。
样例输入
4 4
4 9
样例输出
1624
389112
#include <cstdio>
#include <cstring>
using namespace std;
#define N 21
int imin,imax;
int b[N][N]; //存贮是否为特殊边
int a[N]; //判断该点是否用过 0为没有用过
int result=0; //计数器
int dfs(int i,int n)
{
if(n<=imax&&n>=imin)
result++;
for(int j=1;j<=9;j++)
{
if(a[j]==0) //
{
if(b[i][j]!=0&&a[b[i][j]]==0)
continue; //特殊边的处理
else
{
a[j]=1;
dfs(j,n+1);
a[j]=0;
}
}
}
return 0;
}
int main()
{
while(scanf("%d%d",&imin,&imax)==2)
{
memset(b,0,sizeof(b));
memset(a,0,sizeof(a));
b[1][3]=b[3][1]=2; //记录i--j j--i之间通过的点
b[4][6]=b[6][4]=5;
b[7][9]=b[9][7]=8;
b[1][7]=b[7][1]=4;
b[2][8]=b[8][2]=5;
b[3][9]=b[9][3]=6;
b[1][9]=b[9][1]=5;
b[3][7]=b[7][3]=5;
//初始化数据
dfs(0,0);//从0开始 是为了让各个点都有做出发点的机会
printf("%d\n",result);
result=0;
}
return 0;
}