zoukankan      html  css  js  c++  java
  • 试题 历届试题 带分数 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;
    }
     
  • 相关阅读:
    LeetCode 121. Best Time to Buy and Sell Stock
    LeetCode 221. Maximal Square
    LeetCode 152. Maximum Product Subarray
    LeetCode 53. Maximum Subarray
    LeetCode 91. Decode Ways
    LeetCode 64. Minimum Path Sum
    LeetCode 264. Ugly Number II
    LeetCode 263. Ugly Number
    LeetCode 50. Pow(x, n)
    LeetCode 279. Perfect Squares
  • 原文地址:https://www.cnblogs.com/w-like-code/p/13333896.html
Copyright © 2011-2022 走看看