不懂算法之带分数

来源:互联网 发布:pageoffice php 编辑:程序博客网 时间:2024/05/22 17:00

题目描述

标题:带分数
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
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。


哎,说来也是惭愧,今天去参加校内蓝桥杯选拔赛,编程题最后一题就是这个,前面几道全是用穷举法做,这一道也很自然的想到用穷举法。但是粗略一想,我想先把这个带分数表达式先搞成字符串的形式,但是深入一想。。那尼玛是个无底洞,,果断放弃。之后观察第一个整数和分数的分子分母有什么关系么。。果然,没有,至少我看不出来。怪自己算法思想不够,数学功底欠缺,没有考虑分数的分子分母的位数在N(N<1000*1000&数字1~9分别出现且只出现一次)的条件下是有个上界的。


如果分母是一个五位数,那么分子也必须至少为五位数,因为如果分子不是五位数,那么这个分数一定是小于1的,那也就不可能是这个解了。既然分子分母都是五位数,又只有9个数字,那么分母不可能是五位数。所以这个分数分母的位数最多是4位,最少是1位。


对于第一个整数,由于N<1000*1000,至少存在如下关系不等式:

1 <= 这个整数的位数 <= N的位数;

如果这个整数的位数大于了N的位数,则肯定不是这一种可能了。


既然确定了整数和分母,分子其实可以通过反表示法来表示了:

a + b / c = n;    --->     b = (n - a) * c;


设该等式形式为: 

    left + up / down = n;

核心代码:

        for(down = 1; down < 10000; down++)
{
for(left = 1; left < Pow(10, n_bit); left++)
{
up = (n - left)*down;
   if(Check(left, up, down))
    {
    count++;
    printf("%ld + %ld / %ld\n", left, up, down);
   }    
}
}

解释:

外循环对分母从1到10000(分母是不会超过四位数的)循环,内循环对整数从1到10的n的位数次方(上面分析过整数的位数不会超过n的位数),那么整数和分母的值现在已经是确定了的,所以分子的值也是确定了。剩下的就只是判断这三个数1~9这九个数字是不是有且仅出现了一次即可,交给Check函数来做(如果满足要求,返回1,;否则返回0),如果满足了要求,那么计数变量count就自增1,然后输出这种情况下的表达式。


下面附上完整代码:

#include<stdio.h>int Num_Bit(long x);long Pow(int x, int y);int Check(long left, long up, long down);int main(void){int n;int count = 0;long up, left, down;int n_bit, up_bit, down_bit, left_bit;printf("Enter n: ");scanf("%d", &n);n_bit = Num_Bit(n);for(down = 1; down < 10000; down++){for(left = 1; left < Pow(10, n_bit); left++){up = (n - left)*down;    if(Check(left, up, down))    {    count++;    printf("%ld + %ld / %ld\n", left, up, down);    }    }}printf("count: %d\n", count);return 0;}int Num_Bit(long x){int bit = 0;while(x){x = x/10;bit++;}return bit;}long Pow(int x, int y){int i;long z = 1;for(i = 1; i <= y; i++)    z *= x;        return z;}int Check(long left, long up, long down){int a[9] = {0};int t;while(left){t = left%10;if(t == 0)    return 0;a[t-1]++;left = left/10;}while(up){t = up%10;if(t == 0)    return 0;a[t-1]++;up = up/10;}while(down){t = down%10;if(t == 0)    return 0;a[t-1]++;down = down/10;}for(t = 0; t < 9; t++){if(a[t]!= 1)    return 0;}return 1;}


0 0
原创粉丝点击