带分数|2013年蓝桥杯B组题解析第九题-fishers

带分数

100 可以表示为带分数的形式:100 = 3 + 69258 / 714
还可以表示为:100 = 82 + 3546 / 197
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
题目要求:
从标准输入读入一个正整数N (N<1000*1000)
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
例如:
用户输入:
100
程序输出:
11

再例如:
用户输入:
105
程序输出:
6
资源约定:
峰值内存消耗 < 64M
CPU消耗 < 3000ms

思路:dfs全排列 + 筛选数据,这里的筛选数据方法是:枚举两个端点,也就是分成三个区间判断 a + b/c 是否等于 输入的数n。
代码:
#include<iostream>
using namespace std;

//dfs搜索全部组合,最后筛选满足条件的组合 

int x = 0,  count = 0;
int visited[10];
int ans = 0;
int n;


//将数组区间转化为数字 
int getNum(int list[], int f, int r)  
{  
    int i = 0, num = 0;  
    for (i = f; i <= r; i++)   
        num = list[i] + num * 10; //进位 
    return num;  
}

//筛选出正确的数据: 划分成三个区间 a + b/c (也就等于枚举两个端点) 
int test(int a[]){
    int t = 0;
//  a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i
    //枚举左端点 
    for(int i=1;i<=x;i++){
        double x = 0;
        double y = 0;
        double z = 0;
        //枚举右端点 
        for(int j=i+1;j<9;j++){
            int k1 = i+1;
            int k2 = j+1;
            //求值 
            x = getNum(a,1,k1-1);
            y = getNum(a,k1,k2-1);
            z = getNum(a,k2,9);
            if((y/z) + x == n){
                t++;
            }
        }
    }
    return t;
}

//搜索 全排列 
void dfs(int k,int a[]){
    if(k == 10){
        int tt = test(a);
        if(tt){
            ans+=tt;
        }
        return;
    }
    
    for(int i=1;i<=9;i++){
        //是否使用i这个数:当没有使用过i这个数的值时 就可以用这个数了 
        if(!visited[i]){
            a[k] = i;
            visited[i] = 1; //标记这个数已经用过 
            dfs(k+1,a);
            a[k] = 0; //回溯 
            visited[i] = 0; //回溯标记这个数没有用过 
        }
    }
}

int main(){
    cin>>n;
    int temp = n;
    //统计n总共多少位: 便于dfs的剪枝 
    while (temp != 0)      
    {  
        ++x;  
        temp /= 10;  
    }
    int a[10];
    for(int i = 1;i<=9;i++){
        visited[i] = 0;
    }
    dfs(1,a);
    cout<<ans<<endl;
}
方法二:用algorithm的全排列函数,自己写字符串截取函数(库函数substr效率很低!开辟字符串,拷贝到新空间)
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <string>

using namespace std;

int parse(const char *arr, int pos, int len) {
    int ans = 0;
    int t = 1;
    for (int i = pos + len - 1; i >= pos; --i) {
        ans += (arr[i] - '0') * t;
        t *= 10;
    }
    return ans;
}

int main(int argc, const char *argv[]) {
    int n, ans = 0;
    scanf("%d", &n);
    std::string s = "123456789";
    do {
        const char *str = s.c_str();
        for (int i = 1; i <= 7; ++i) {
//            string a = s.substr(0, i);
            int inta = parse(str, 0, i);
            if (inta >= n)break;

            for (int j = 1; j <= 9 - i - 1; ++j) {
//                string b = s.substr(i, j);
//                string c = s.substr(i + j)
//                int intb = atoi(b.c_str());
//                int intc = atoi(c.c_str());
                int intb = parse(str, i, j);
                int intc = parse(str, i + j, 9 - i - j);
                if (intb % intc == 0 && inta + intb / intc == n)ans++;
            }
        }
    } while (std::next_permutation(s.begin(), s.end()));
    printf("%d\n", ans);
    return 0;
}

转载于:https://www.cnblogs.com/fisherss/p/10326701.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值