蓝桥杯(历届真题)——带分数 dfs遍历

算法描述

问题描述

100 可以表示为带分数的形式:100 = 3 + 69258 / 714。

还可以表示为:100 = 82 + 3546 / 197。

注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。

类似这样的带分数,100 有 11 种表示法。

输入格式

从标准输入读入一个正整数N (N<1000*1000)

输出格式

程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。

注意:不要求输出每个表示,只统计有多少表示法!

样例输入1

100

样例输出1

11

样例输入2

105

样例输出2

6

思考过程

拿到题想到的思路就是用一个长度为9的数组存储这九个数,满足每一位上数字不重复。然后往这九个数中间插运算符,计算结果为输入的数时总数加一就可以。
然后下手写的时候发现我不会遍历这九种数的情况,愁,毕竟我是啥算法都不会的菜鸡×。但是菜鸡会请教大佬,大佬说用dfs遍历很简单。然后给了我一段程序,我就就着程序改的。
dfs深度优先遍历算法简单来说就是,确定一个初始点,然后找其相邻的第二个点,如果点存在并且没有遍历过,就将点作为起始点再进行如上规律遍历,否则找到下一条路径。
伪代码如下:
(1)访问顶点v;visited[v]=1;//算法执行前visited[n]=0

(2)w=顶点v的第一个邻接点;

(3)while(w存在)

       if(w未被访问)

               从顶点w出发递归执行该算法; 
       w=顶点v的下一个邻接点;

这样就第一组产生的数据就是123456789,之后判断走到头了,就return一个,发现仍然没有满足条件的,就再回溯一个,这样数组变成了123456700,倒数第二位又出现一种情况就是9,最后一位8,即123456798 。其实这样说很抽象,画个图表示一下这个过程会方便理解一些。当然这是萌新的方法,一眼就能看出来的大佬就不要用啦~
通过这种方法遍历出数组后。针对每次生成出数组的情况,对其进行处理。三个数的长度均为1-7的范围内,设置一个函数,将char数组里存放的数字转换为int型数字返回,参数为起始点的下标和数字长度。返回数字后计算num1 + num2 / num3 == N。因为输入的N为正数,所以num2 / num3一定是可整除的,并且num2 >= num3 。所以在判断条件时可以利用这一点减少循环次数。
然后就没了。。

代码表示

/* 0v0 AUTHER: 0_Re5et */

#include <stdio.h>
#include <stdlib.h>

int p[9] = {0};
//int p[9] = {3, 6, 9, 2, 5, 8, 7, 1, 4};
int N, K=1;
int NUM = 0;

// 判断数字是否重复出现
int inc(int t)
{
    int i;

    for(i=0; i<9; i++)
    {
        if(p[i] == t)
        {
            return 1;
        }
    }
    return 0;
}

// 输出数组
void Put()
{
    int i, j;
    int num1, num2, num3;

// for(i=0; i<9; i++)
// {
// printf("%d ", p[i]);
// }
// printf("\n");
// system("pause");

    for(i=1; i<=7; i++)
    {
        for(j=1; j<=7-i+1; j++)
        {
            if(j < 9-i-j)
            {

                continue;
            }
            else
            {
                num1 = ToNum(0, i);
                num2 = ToNum(i, j);
                num3 = ToNum(i+j, 9-i-j);
// printf("%d %d %d\n", num1, num2, num3);
// system("pause");
                if(((num2 % num3) == 0) && (num1 + num2 / num3) == N)
                {

                    //printf("hahahahaha!!!\n\n");
                    NUM++;
                }
                else
                {
                    continue;
                }
            }

        }
    }


}

// dfs算法
void dfs(int u)
{
    int i, j;
    if(u == 9)
    {
        Put();
        return;
    }
    for(i=1; i<=9; i++)
    {
        if(!inc(i))
        {
            p[u] = i;
            dfs(u+1);
            p[u] = 0;
        }
    }
}


// 抽取数组一部分变成数字
int ToNum(int s, int n)
{
    int i, temp = 0;

    for(i=0; i<n; i++)
    {
        temp = temp * 10 + p[s + i];
    }

    return temp;
}


int main()
{

    scanf("%d", &N);

    dfs(0);
// Put();

    printf("%d", NUM);  

    return 0;

}

注意事项

注意插运算符的时候两个for循环的初始值和结束条件,最开始写的时候就写错了,导致了数组超限然后程序崩溃。
再一个就是注意递归的时候return的使用,用不好就不知道程序执行到哪里去了。很迷
如果想跳出递归又没办法通过return跳出,可以设置标志位在递归函数的开头,直接判断当flag值为1的时候,直接return,这样就return到最外面去了。
然后注意本题中dfs执行完了之后数组置零的过程,起到visit数组标记的作用。
然后把该弄成全局变量的弄一下吧,传参数麻烦的不行。。←
以上。

    原文作者:DFS
    原文地址: https://blog.csdn.net/kanamisama0/article/details/61028335
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞