题目描述

 

 

很多手机或平板电脑软件都可以设置手势密码,在设置了手势密码后,进入程序时,首先要输入手势密码。

手势密码最少选择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

题意:就是我们手机的手势密码,比较简单理解

解题思路:我把这个题看作是走迷宫一类的问题,每一个点可以向不同的方向走去,走完迷宫截至,有多少种走法

那就按照走迷宫的模板来,

第一 :方向dir,每一个点有上下左右4种,斜着走4中,以及”日“字走8种,总共就是16种走法

我用dir存储

第二:对于走到边界怎么处理,比如  4->2->3->1是可行的,如何处理,方法是继续向“墙壁”走一步,看是否可行

第三:优化,也就是剪枝,很明显,此题有很大的对称性,4个角(也就是1,3,7,9)从这几个起点出发的步数是一样的

2,4,6,8这几个点出发的步数也是一样的,5这个点就单独处理即可

answer=

(step)(  dfs(stpe,1,1)*4+dfs(step,1,2)*4+dfs(step,2,2)  )         MAX>=step>=MIN 

具体看代码

网上还有一种解法,我就不多说了(我还没在网上发现我这个解法的...=v=...)

#include <bits/stdc++.h>

using namespace std;

int z[10][10];
int dir[16][2]= {1,0,0,1,-1,0,0,-1,//s上下左右
                 1,1,-1,-1,-1,1,1,-1,//斜着走
                 2,1,2,-1,1,2,-1,2,-2,1,-2,-1,1,-2,-1,-2//走日字
                };//方向坐标
int dfs(int step,int x,int y)
{
    int ans=0;
    if(step==1)  return 1;
    for(int i=0; i<16; i++)
    {
        int xx,yy;
        xx=x+dir[i][0];
        yy=y+dir[i][1];
        if(xx>=1 && yy>=1 && xx<=3 && yy<=3)//在3*3的迷宫里面
        {
            if(z[xx][yy]==0)//可以走
            {
                z[xx][yy]=1;
                ans+=dfs(step-1,xx,yy);
                z[xx][yy]=0;
            }
            else//撞墙了,继续判断
            {
                int xxx=xx+dir[i][0];
                int yyy=yy+dir[i][1];
                if(xxx>=1 && xxx<=3 && yyy>=1 && yyy<=3 && !z[xxx][yyy])
                {
                    z[xxx][yyy]=1;
                    ans+=dfs(step-1,xxx,yyy);
                    z[xxx][yyy]=0;
                }
            }
        }
    }
    return ans;
}
int solve(int step)
{

    int ans=0;
    z[1][1]=1;
    ans+=4*dfs(step,1,1);
    z[1][1]=0;

    z[1][2]=1;
    ans+=4*dfs(step,1,2);
    z[1][2]=0;

    z[2][2]=1;
    ans+=dfs(step,2,2);
    z[2][2]=0;
    return ans;
}
int main()
{
    int MIN,MAX;
    while(cin>>MIN>>MAX)
    {
        int ans=0;
        memset(z,0,sizeof z);
        for(int i=MIN; i<=MAX; i++)//每一次的步数
            ans+=solve(i);
        cout<<ans<<endl;
    }
    return 0;
}