题目描述
很多手机或平板电脑软件都可以设置手势密码,在设置了手势密码后,进入程序时,首先要输入手势密码。
手势密码最少选择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;
}