方格填数(递推dfs,状态编码)

题目

如下的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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值