(上图是九宫格点对应的编号)
用手指依次划过九宫格中的几个点,从而构成一个图案,将这个图案作为开机的密码。每个点最多使用一次,手指可以水平,竖直或者倾斜移动,但是不可以跳过未使用过的点。如果按编号对应的话,右图中的密码是147896325.另外,1524, 1832,5912是可以接受的,而1952是不能接受的。1234与1423是不同的方案
状态压缩做的题还是太少了,这算作第二题吧,主要是怎么用状压。
思想:
d[i][j]表示以i结尾,状态是j的排列数。
a[t1][t2]表示从t1到t2之间的数。
#include<iostream>
using namespace std;
int a[11][11];
int dp[11][1000];//dp[i][j]表示以i结尾状态为j的排列数
void init()
{
a[1][3]=2,a[1][7]=4,a[1][9]=5;
a[2][8]=5;
a[3][1]=2,a[3][9]=6,a[3][7]=5;
a[4][6]=5,a[6][4]=5;
a[7][1]=4,a[7][9]=8,a[7][3]=5;
a[8][2]=5;
a[9][7]=8,a[9][1]=5,a[9][3]=6;
for(int i=0;i<9;i++)
dp[i][1<<i]=1;
for(int i=0;i<(1<<9);i++)
{
for(int j=0;j<9;j++)
if(i&(1<<j))
{
for(int k=0;k<9;k++)
if(!(i&(1<<k)))
{
int t1,t2,t3;
t1=j+1;
t2=k+1;
t3=a[t1][t2]-1;
if(t3<0||((i&(1<<t3))))//这里t3必须在i中
{
dp[k][i|(1<<k)]+=dp[j][i];
}
}
}
}
}
int get(int n)
{
int ans=0,cnt=0;
for(int j=0;j<9;j++)
{
for(int i=0;i<(1<<9);i++)
{
if(i&(1<<j))
{
cnt=0;
for(int k=0;k<9;k++)
if(i&(1<<k))
cnt++;
if(cnt==n)
ans+=dp[j][i];
}
}
}
return ans;
}
int main()
{
init();
int n;
cin>>n;
cout<<get(n)<<endl;
return 0;
}