题目描述
标题:带分数
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;
}