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

    xiaoxiao2021-03-25  86

    算法描述

    问题描述

    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数组标记的作用。 然后把该弄成全局变量的弄一下吧,传参数麻烦的不行。。← 以上。

    转载请注明原文地址: https://ju.6miu.com/read-17623.html

    最新回复(0)