zoukankan      html  css  js  c++  java
  • 蓝桥杯 剪邮票 DFS (不错的题目)

    剪邮票

    如【图1.jpg】, 有12张连在一起的12生肖的邮票。
    现在你要从中剪下5张来,要求必须是连着的。
    (仅仅连接一个角不算相连)
    比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。

    请你计算,一共有多少种不同的剪取方法。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    using namespace std;
    
    const int maxn = 14;
    int maze[3][4];
    int num[6];
    int have[13];          // 用了对从全排列中 选出来 5个数 ,进行 标志 (回溯: 标志为true后,需要换回false) 
    bool used[3][4];       //这个是 从全排列中选出来5个数,进行DFS搜索是否连续用的标志数组 , 标志为true后,不需要换回false 
    bool visit[13];        //进行全排列用的标志数组 
    int ans;
    int Count = 0;
    int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};  //方向 
    
    void init();
    void dfs_find(int r, int c);
    bool judge(int r, int c);
    void solve();
    
    void init()
    {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 4; j++) {
                maze[i][j] = i*4 + j + 1;
            }
        } 
    }
    
    bool judge(int r, int c)
    {
        return (r >= 0 && r < 3) && (c >= 0 && c < 4);
    }
    
    void dfs_find(int r, int c)
    {
        for (int i = 0; i < 4; i++)
        {
            int nx = r + dir[i][0], ny = c + dir[i][1];
            //这个位置不是have标记位置(have里标记过的元素,是全排列找到的五个元素),或者已经访问过了 
            if (judge(nx, ny) && !used[nx][ny] && have[maze[nx][ny]]) {  
                used[nx][ny] = true;    //不需要换回 false, 除非出现另外一组5个数的时候 
                Count++;                //连续的数++ 
                dfs_find(nx, ny);       //对一个点进行DFS 
            }
        }
    }
    
    void solve()
    {
        memset(have, 0, sizeof(have));
        memset(used, false, sizeof(used));
        for (int i = 1; i <= 5; i++) {
            have[ num[i] ] = 1;        //对5个数的位置进行标记 
        }
        
        for (int i = 0; i < 12; i++)
        {
            int r = i / 4;    //对应行
            int c = i % 4;    //对应列 
            if ( have[maze[r][c]] )     // 对找到的 5个数字(被标记1的),开始DFS搜索 
            {
                Count = 1;              //开始为1 
                used[r][c] = true;      //由标记的第一个数开始, 向其他标记的数 进行DFS, 找到则 Count++ 
                dfs_find(r, c);
                break;
            }
        }
        if (Count == 5) {               //全排列找到的5个数, 是相邻的, 则ans++ 
            ans++;
        }
    }
    //创建5个数的组合 
    void Start_DFS(int cur)
    {
        if (cur == 6)   //找到了5个数 
        {
            solve();    //对找到的5个数,进行排列组合 
            return;
        }
        
        //1到12 这 12个数 挨个遍历 -- 并进行DFS搜索 
        for (int i = num[cur - 1] + 1; i < 13; i++)    
        {
            if (!visit[i])          
            {
                visit[i] = true;
                num[cur] = i;       //存数,  对12个数进行全排列,从中选5个数,再进行排列组合 
                Start_DFS(cur + 1); //下一个数
                visit[i] = false;   
            }
        } 
    }
    
    int main()
    {
        init();
        Start_DFS(1);
        printf("%d
    ", ans);
    }
    
     

    算法思路:

    1. 先全排列,从全排列1~12,从中选5个数,进行排列组合;

    2. 对选中的5个数标志;

    3. 循环找到第一个 第一个被标志的位置,并DFS递归寻找,他的dir方向的数字,是否是从全排列中选出来的其他数字.

    详细看注释.

    参考了这篇博客:http://blog.csdn.net/wuxiushu/article/details/51207533

  • 相关阅读:
    软工网络15个人阅读作业1
    JAVA课程设计-猜数游戏 201521123017
    201521123017 《Java程序设计》第14周学习总结
    201521123017 《Java程序设计》第13周学习总结
    201521123017 《Java程序设计》第12周学习总结
    个人作业5---软工个人总结
    网络软工个人作业4——Alpha阶段个人总结
    软件工程网络15个人作业3(201521123028 李家俊)
    软工网络15结对编程练习
    软件工程网络15个人阅读作业2(201521123028李家俊)
  • 原文地址:https://www.cnblogs.com/douzujun/p/6670663.html
Copyright © 2011-2022 走看看