zoukankan      html  css  js  c++  java
  • 第七届 蓝桥杯 方格填数 dfs

    如下的10个格子 
    方格 
    填入0~9的数字。要求:连续的两个数字不能相邻。 (左右、上下、对角都算相邻) 
    一共有多少种可能的填数方案? 
    请填写表示方案数目的整数。 
    注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

    方法一:遍历

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int map[6][6];
    int ans=0;
    int Abs(int i,int j)//判断 8个方向 
    {
        if(abs(map[i-1][j]-map[i][j])==1)
            return 0;
        if(abs(map[i+1][j]-map[i][j])==1)
            return 0;
        if(abs(map[i][j+1]-map[i][j])==1)
            return 0;
        if(abs(map[i][j-1]-map[i][j])==1)
            return 0;
        if(abs(map[i-1][j-1]-map[i][j])==1)
            return 0;
        if(abs(map[i+1][j-1]-map[i][j])==1)
            return 0;
        if(abs(map[i-1][j+1]-map[i][j])==1)
            return 0;
        if(abs(map[i+1][j+1]-map[i][j])==1)
            return 0;
        return 1;        
    }
    int f()//判断相邻的数是否连续 
    {
        if(Abs(1,3)&&Abs(2,1)&&Abs(2,2)&&Abs(2,3)&&Abs(2,4)&&Abs(3,2))
            return 1;
        return 0; 
    } 
    int main()
    {    
        memset(map,-2,sizeof(map));
        int  a[] = {0,1,2,3,4,5,6,7,8,9};
        do{
            map[1][2]=a[0];
            map[1][3]=a[1];
            map[1][4]=a[2];
            map[2][1]=a[3];
            map[2][2]=a[4];
            map[2][3]=a[5];
            map[2][4]=a[6];
            map[3][1]=a[7];
            map[3][2]=a[8];
            map[3][3]=a[9];
            ans+=f();
        }while(next_permutation(a,a+10));
        cout<<ans<<endl;
        return 0;
    }

    方法二: dfs

    #include <stdio.h>
    #include <stdlib.h>
     
     
    int ans = 0, flag[10] = {0};
     
     
    int Check(int a[][4], int x, int y)
    {
        static int dx[] = {0, -1, -1, -1}, dy[] = {-1, -1, 0, 1};
        
        for(int i = 0; i < 4; i ++)
            if( (x + dx[i] >= 0 && x + dx[i] < 3) && (y + dy[i] >= 0 && y + dy[i] < 4) )
            {
                if( 1 == abs(a[x][y] - a[ x + dx[i] ][ y + dy[i] ]))
                    return 0;
            }
     
     
        return 1;
    }
     
     
    void dfs(int a[][4], int x, int y)
    {
        if(2 == x && 3 == y){
            ans ++;
            return ;
        }
        
        for(int num = 0; num <= 9; num ++)
            if(!flag[num]){
                a[x][y] = num;
                flag[num] = 1;
                
                if(Check(a, x, y)){
                    if(y + 1 < 4)
                        dfs(a, x, y + 1);
                    else
                        dfs(a, x + 1, 0);
                }
                flag[num] = 0;
            }
    }
     
     
    int main()
    {
        int a[3][4] = {-20};
        dfs(a, 0, 1);
        printf("%d", ans);
        return 0;
    }

    方法三:

    看到这题第一个想到的方法就是回溯,就很像八皇后,能填进去就填,填不进去就看下一个位置(我做的是0---9不重复使用)

    我感觉这题麻烦就在判断上

    1.首先要判断一个点的8个方向相减的绝对值是否为1,为1不能填入,不为1判断是否使用过这个数,没使用填入 进行下一个位置

    2.如果填入的位置到达最后一列应该换行看下一行的第一个位置进行判断

    3.填到最后每一个情况总sum++就行了

    上代码

    #include<iostream>
    using namespace std;
    int a[3][4];
    int num = 0;
    int v[10] = {0};
    int pd(int k, int i, int j){//这个就是判断啦。。写的有点繁琐
        if (i-1>=0 && (a[i - 1][j] == k - 1 || a[i - 1][j] == k + 1) )
            return 0;
        if (j-1>=0 && (a[i][j - 1] == k + 1 || a[i][j - 1] == k - 1) )
            return 0;
        if (i-1>=0 && j-1>=0 && (a[i - 1][j - 1] == k + 1 || a[i - 1][j - 1] == k - 1))
            return 0;
        if (i-1>=0 && j+1<4 && (a[i - 1][j + 1] == k + 1 || a[i - 1][j + 1] == k - 1))
            return 0;
        if (j + 1 < 4 && (a[i][j + 1] == k + 1 || a[i][j + 1] == k - 1))
            return 0;
        if (i + 1 < 3 && (a[i + 1][j] == k + 1 || a[i + 1][j] == k - 1))
            return 0;
        if (i + 1 < 3 && j - 1 >= 0 && (a[i + 1][j - 1] == k + 1 || a[i + 1][j - 1] == k - 1))
            return 0;
        if (i + 1 < 3 && j + 1 < 4 && (a[i + 1][j + 1] == k + 1 || a[i + 1][j + 1] == k - 1))
            return 0;
        return 1;
    }
    void f(int i, int j){
        if (i == 2&&j==3){//已经填入到最后一个说明这种情况满足,num++
            num++;
            return;
        }
            for (int k = 0; k <= 9; k++){
                if (pd(k, i, j)&&v[k]==0) {//判断8个方向是否能填入,并且是否用过
                    v[k] = 1;
                    a[i][j] = k;
                    if (j == 3)//到达最后一列记得换行
                        f(i + 1, 0);
                    else
                        f(i, j + 1);
                    a[i][j] = -9;
                    v[k] = 0;
                }
            }
    }
    int main(){
        for (int i = 0; i < 3; i++)//这里我将所有数赋值-9,因为第一个和最后一个不需要赋值,避免干扰
            for (int j = 0; j < 4; j++)
                a[i][j] = -9;
        f(0, 1);
        printf("%d", num);
        return 0;
    }
    #include <bits/stdc++.h>
    using namespace std;
    
    /*本来要判断八个格子,
     *但是由于是从左往右从上往下填的,
     *只要判断左、左上、上、右上
    */
    const int dx[]={0,-1,-1,-1};
    const int dy[]={-1,-1,0,1};
    const int INF=1e9;
    bool used[10];
    int ans=0;
    int a[5][5];
    
    bool alright(int n,int x,int y)
    {
        for (int i=0;i<4;i++) {
            int xx=x+dx[i],yy=y+dy[i];
            if (xx<1||yy<1||xx>3||yy>4) continue;
            if (abs(n-a[xx][yy])==1) return false;
        }
        return true;
    }
    
    void dfs(int x,int y)
    {
        if (x==3&&y==4) {
            ans++;
            return;
        }
        for (int i=0;i<=9;i++) {
            if (!used[i]&&alright(i,x,y)) {
                a[x][y]=i;
                used[i]=true;
                if (y==4) dfs(x+1,1);
                else dfs(x,y+1);
                used[i]=false;
                a[x][y]=-INF;
            }
        }
    }
    
    int main()
    {
        for (int i=1;i<=3;i++) {
            for (int j=1;j<=4;j++) {
                a[i][j]=-INF;
            }
        }
        dfs(1,2);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    datagridview 批量更新、日期设置、指定列弹出右键菜单
    CAD ObjectARX扩展工具的源码(二)
    ObjextARX-VS2005-字符串转换
    二叉搜索树(二叉查找树)
    贪婪算法-货物装载问题
    Messagebox.Show()常用参数的讨论
    关于矩形排样问题(三)
    单纯形法实现一维管材排料最优化
    [转载]共享一些常用的代码
    转载]取硬盘ID的API实现
  • 原文地址:https://www.cnblogs.com/hcw110/p/10580753.html
Copyright © 2011-2022 走看看