hnust 1606 手勢密碼(DFS)
題目描述
很多手機或平板電腦軟體都可以設定手勢密碼,在設定了手勢密碼後,進入程式時,首先要輸入手勢密碼。
手勢密碼最少選擇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;
}