蓝桥杯_2016年第七届C/C++B组—6.方格填数 【DFS】

本文探讨了一道关于在10个格子里填入0~9数字的问题,要求连续两个数字不能相邻(包括对角线)。通过递归回溯算法解决此问题,详细介绍了算法的实现过程及代码。

题目描述:

如下的10个格子



填入0~9的数字。要求:连续的两个数字不能相邻。
(左右、上下、对角都算相邻)

一共有多少种可能的填数方案?

请填写表示方案数目的整数。
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

解题思路:

这是一道考察递归回溯的题目。首先需要定义一个Map[][]的二维数组来存放数值,一个标记数组判断该数值是否使用。第一个方格为递归的起点,可以放0-9十种情况,所以递归的方法也就是十种。递归函数传入的参数是填入数值的个数。当填入的数字大于十个的时候,就停止递归,然后填数的种类加一;当参数小于等于十次的时候,就需要判断0-9个数值中的一个是否可以继续递归下去,如果可以,对该数值进行标记,并把该数值存到对应的Map[][]数组里面,最后递归完以后回溯到调用递归之前的状态。
这里要注意,Map[][]里面的值一开始都要赋值11(小于等于-2,大于等于11),这样0-9所有的数都不能与之相邻。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>

using namespace std;
int a[10];
int Map[5][6];//
int ans;
int dir[8][2]= {1,0,-1,0,0,1,0,-1,1,1,1,-1,-1,1,-1,-1};
bool judge(int num,int t)//判断该数值是否可以存入Map[][]数组中
{
    int temp=1;
    int x=num/4+1;//表示横坐标
    int y=num%4+1;//表示纵坐标
    for(int i=0; i<8; i++)//八个方向
    {
        int x1=x+dir[i][0];
        int y1=y+dir[i][1];
        if(Map[x][y]==Map[x1][y1]+1||Map[x][y]==Map[x1][y1]-1)//判断数值是否相邻
        {
            temp=0;
            break;
        }
    }
    if(a[t]==1)//判断是否被标记
        temp=0;
    if(temp==0)
        return false;
    else
        return true;
}
void dfs(int n)
{
    n++;
    if(n==11)//如果填入的数值个数大于10就停止递归,并且种类加一
    {
        ans++;
        return ;
    }
    for(int i=0; i<=9; i++)
    {
        Map[n/4+1][n%4+1]=i;
        if(judge(n,i))//符合条件进行递归,不符合Map[][]还原成以前的状态
        {
            a[i]=1;
            dfs(n);
            Map[n/4+1][n%4+1]=11;//回溯Map
            a[i]=0;//回溯标记数组a
        }
        else
            Map[n/4+1][n%4+1]=11;
    }
}
int main()
{
    memset(a,0,sizeof(a));
    ans=0;
    for(int i=0; i<=4; i++)
    {
        for(int j=0; j<=5; j++)
            Map[i][j]=11;
    }
    for(int i=0; i<=9; i++)//起点的10种可能
    {
        a[i]=1;
        Map[1][2]=i;
        dfs(1);
        Map[1][2]=11;
        a[i]=0;
    }
    cout<<ans<<endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值