• 试题 历届试题 带分数 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
    解题思路:
    思路1:用dfs暴力搜索,加上适当条件剪枝以降低时间复杂度。可以看到带分数的形式:
    n = a + b/c 
    首先有 a<n;b/c应为正整数,所以b%c==0且b>c(b数字长度大于等于c)。
    利用上述条件作为剪枝条件。
    实现时需要先计算n的长度,以此确定a的最大长度(其实对于a用大于等于n长度的都可以,因为最后a>=n的会被剪枝)和b的最小长度(大于等于c的长度)
    另外用count()函数计算num[]某区间按顺序组成的数字,注意区间是左闭右开。[ )
    实现代码:
    #include<cstdio>
    
    const int Length = 9;//1-9
    
    //输入
    int n;
    
    int num[Length];      //保存数字1-9
    bool flag[Length+1]; //数字i是否被使用 
    int res = 0;        //保存带分数表示法数目 
    int length;           //输入n的位数(长度) 
    
    //计算num[]从[start,end)的元素排列 
    int count(int start,int end)
    {
        int s = 0;
        for( int i=start; i<end; i++ )
        {
            s = s*10 + num[i];
        }
        return s;
    }
    
    //计算某一排列下带分数的个数 
    void rec()
    {
         
        for( int i=1; i<=length; i++ )
        {
            int a = count(0,i); //num[k](0<=k<i)的下标元素排列 
            if( a>=n )    return;//剪枝
            for( int j = i+(length-i)/2+1; j<Length; j++ )
            {    // j-i >= (Length-i)/2 因为b的长度>=c的长度  但因为count()是右开,所以再+1 
               // j<Length 最后给c至少留一位(要注意count()是右开 很容易出错) 
                int b = count(i,j); //num[k](i<=k<j)的下标元素排列 
                int c = count(j,Length); ////num[k](j<=k<Length)的下标元素排列 
    if( b>c && b%c==0 && n==a+b/c ){ res++; } } } } //dfs找到所有排列 void dfs(int k) { //找到了某种全排列 if( k==Length ){ rec(); return; } //找全排列 for( int i=1; i<=Length; i++ ) { if( flag[i] ) continue; //数字i已经在num[]里了 跳过这次循环 flag[i] = true; num[k] = i; dfs( k+1 ); flag[i] = false; //回溯 num[]元素可以直接覆盖 所以不用回溯 } } void solve() { //计算n的位数 int n_ = n; while( n_ ) { length++; n_ /= 10; } dfs( 0 ); //num[]从下标0开始找全排列 printf("%d ",res); } int main() { scanf("%d",&n); solve(); return 0; }

    思路2:与思路1大体相同,唯一不同的是其num[] 1-9的全排列是用C++全排列函数next_permutation(int *begin,int *end)  参考https://www.cnblogs.com/cstdio1/p/11311500.html

    在<algorithm>下,返回bool类型值,当没有下一排列时返回false,参数为需要排列的地址(左闭右开),其next表示字典序从小到大(对应有prev_permutation())

    注意:用next_permutation()求全排列时数组初始为升序排列。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    const int Length = 9;//一位数1-9
    
    //输入
    int n;
    
    int length;//n位数 
    int num[Length]; 
    int ans; //计算符合条件的数目 
    
    //计算num[]从[start,end)元素和 
    int count(int start,int end)
    {
        int s = 0;
        for( int i=start; i<end; i++ )
        {
            s = s*10 + num[i];
        }
        return s;
    }
    
    void solve()
    {
        //初始化数字数组及输入n位数 
        for( int i=0; i<Length; i++){
            num[i] = i+1;
        } 
        
        int n_ = n;
        while( n_ )
        {
            length++;
            n_ /= 10;
        }
        
        do
        {
            for( int i=1; i<=length; i++ )// x最大为length位数 
            {
                int a = count(0,i);//遍历length位数的所有数字
                if( a<n )
                {//剪枝 
                    for( int j=i+(length-i)/2+1; j<Length; j++ )// j-i>=(length-i)/2
                    { 
                        int b = count(i,j), c = count(j,Length);
                        if( b>c && b%c==0 && n==a+b/c )
                        {
                            ans++;
                        }    
                    }
                }    
            }    
        }while( next_permutation(num,num+Length));//num的全排列 
        
        printf("%d
    ",ans);
    } 
    
    int main()
    {
        scanf("%d",&n);
        
        solve();
        
        return 0;
    }
     
  • 相关阅读:
    剑指offer--29.从上往下打印二叉树
    剑指offer--28.栈的压入、弹出序列
    剑指offer--27.包含min函数的栈
    剑指offer--26.顺时针打印矩阵
    剑指offer--25.二叉树的镜像
    剑指offer--24.树的子结构
    剑指offer--23.合并两个排序的链表
    剑指offer--22.反转链表
    剑指offer--21.链表中倒数第k个结点
    剑指offer--20.矩形覆盖
  • 原文地址:https://www.cnblogs.com/w-like-code/p/13333896.html
Copyright © 2020-2023  润新知