题目
如下的10个格子
填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)
一共有多少种可能的填数方案?
题解
本题其实并不需要状态编码,因为从1行2列开始填和从1行3列开始填,所得到的状态是不一样的,不像 蓝桥杯的7段码 中状态会有重叠。写到一半才注意到,但是可以练练状态编码。
状态编码:
这里使用映射:map<pair<int,int>,int> mp,如1行1列映射为数字0,1行2列映射为数字1,1行3列映射为数字2,假如1行2列里填的数为0,1行3列里填的数字为1,那么得到的状态编码为0*10^1+1*10^2
。如果访问到该状态,就将该状态加入到set集合中,代表已经访问过。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int my_mp[4][5];//1~3 1~4
int ans=0;
map<pair<int,int>,int> mp;
set<ll> my_st;
ll my_pow(int t)//10^t
{
ll a=1;
for(int i=0;i<t;i++)
{
a=a*10;
}
return a;
}
ll convert()
{
ll num=0;
for(int i=1;i<=3;i++)
{
for(int j=1;j<=4;j++)
{
if(my_mp[i][j]==-2) continue;
num+=(ll)(my_mp[i][j])*my_pow(mp.find(make_pair(i,j))->second);
}
}
return num;
}
void dfs(int row,int col,int num)
{
my_mp[row][col]=num;
//cout<<row<<" "<<col<<" "<<num<<endl;
if(num==9)
{
ll temp=convert();
if(my_st.find(temp)==my_st.end())
{
ans++;
my_st.insert(temp);
//cout<<"符合条件的结果"<<temp;
}
//cout<<"结束----------------------------------------------------"<<endl;
}
for(int i=1;i<=3;i++)
{
for(int j=1;j<=4;j++)
{
if(my_mp[i][j]==-2 || my_mp[i][j]>=0) continue;
//cout<<"i"<<i<<"j"<<j;
//cout<<"abs(i-row)"<<abs(i-row);
//cout<<"abs(j-col)"<<abs(j-col)<<endl;
if(abs(i-row)<=1 && abs(j-col)<=1) continue;
dfs(i,j,num+1);
}
}
my_mp[row][col]=-1;
}
void init()
{
int s=0;
for(int i=1;i<=3;i++)
{
for(int j=1;j<=4;j++)
{
pair<int,int> p(i,j);
mp[p]=s;
s++;
}
}
for(int i=1;i<=3;i++)
{
for(int j=1;j<=4;j++)
{
my_mp[i][j]=-1;
}
}
my_mp[1][1]=-2;
my_mp[3][4]=-2;
}
int main()
{
init();
for(int i=1;i<=3;i++)
{
for(int j=1;j<=4;j++)
{
if(my_mp[i][j]==-2) continue;
//cout<<"-------------------------------------------------"<<endl;
dfs(i,j,0);
}
}
cout<<ans;
}