求助:手勢密碼算法題



手勢密碼題
9個圓圈代買1-9,求所有合法的密碼數
注意:要求密碼長度大於等於2,密碼不能有重復,密碼上相鄰的數字在圖形是可連,即數字1后面可以接2、4、5、6、8,不能接3、7、9。
不能接3、7、9是因為如果與3、7、9相連必然經過2、4、5
 

2 个解决方案

#1



int main()
{
const int p1[]={2,4,5,0};
const int p2[]={1,3,4,5,6,0};
const int p3[]={2,5,6,0};
const int p4[]={1,2,5,7,8,0};
const int p5[]={1,2,3,4,6,7,8,9,0};
const int p6[]={2,3,5,8,9,0};
const int p7[]={4,5,8,0};
const int p8[]={4,5,6,7,9,0};
const int p9[]={5,6,8,0};
const int *pp[]={p1,p2,p3,p4,p5,p6,p7,p8,p9};
bool pNotUsed[9]={true,true,true,true,true,true,true,true,true};
char pResult[10];
int i,iCount=0;

for (i=0;i<9;i++)
{
pNotUsed[i]=false;
Enum(i,pp,pNotUsed,pResult,0,&iCount);
pNotUsed[i]=true;
}

return 0
}

void Enum(int iThis,const int *pp[],bool pNotUsed[],char pResult[],int iLevel,int *pCount)
{
int i,n;

pResult[iLevel]='1'+iThis;
if (iLevel>0)
{
(*pCount)++;
pResult[iLevel+1]=0;
printf("%d: %s\n",*pCount,pResult);
}
for (i=0;pp[iThis][i]>0;i++)
{
n=pp[iThis][i]-1;
if (pNotUsed[n])
{
pNotUsed[n]=false;
Enum(n,pp,pNotUsed,pResult,iLevel+1,pCount);
pNotUsed[n]=true;
}
}
}

#2


一共就9個點,暴力搜索應該也行的吧,但是稍微觀察一下,我們就能做一個不小的優化:
(1)由對稱性可知,所有合法的密碼路徑起點一共分為3種:
以1為首的合法的密碼路徑,與以3、7、9為首的合法路徑個數相同,設個數為X
以2為首的合法的密碼路徑,與以4、6、8為首的合法路徑個數相同,設個數為Y
以5為首的合法的密碼路徑,設個數為Z
則所有合法的密碼路徑個數Sum = 4X+4Y+Z
(2)用搜索的方式確定總長度為Len的密碼的下一個數字
用矩陣illegal[i][j]表示數字i與數字j(i != j)直接相連的合法與否,則不難得到1與3、1與7、1與9,2與8,4與6互聯是不合法的
代碼也不難寫:

#include <cstdio>

bool used[10] = {0};
bool illegal[10][10] = {0};

void init()
{
    illegal[1][3] = true;
    illegal[1][7] = true;
    illegal[1][9] = true;
    illegal[2][8] = true;
    illegal[3][1] = true;
    illegal[3][7] = true;
    illegal[3][9] = true;
    illegal[4][6] = true;
    //link 5 with any other is legal
    illegal[6][4] = true;
    illegal[7][1] = true;
    illegal[7][3] = true;
    illegal[7][9] = true;
    illegal[8][2] = true;
    illegal[9][1] = true;
    illegal[9][3] = true;
    illegal[9][7] = true;
}
int dfs(int st, int remainLen)
{
    if(remainLen == 1) return 1;
    
    int sum = 0;
    used[st] = true; --remainLen;//mark used, decrease remaining length
    for(int i = 1; i < 10; ++i){ //here it's not possible to link st to st
        if(!used[i] && !illegal[st][i]) sum += dfs(i, remainLen);
    }
    used[st] = false;            //recover situation

    return sum;
}
int howmany()
{   
    int X = 0, Y = 0, Z = 0, len;
    
    for(len = 2; len < 10; ++len) X += dfs(1, len);
    for(len = 2; len < 10; ++len) Y += dfs(2, len);
    for(len = 2; len < 10; ++len) Z += dfs(5, len);
    
    return (X<<2) + (Y<<2) + Z;
}

int main()
{
    init();
    printf("%d legal passwords\n", howmany());
    
    return 0;
}


最后,以上所述並不保證正確,更不保證最優,拋磚引玉,僅供參考



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com