第四届蓝桥杯编程题:带分数

标题:带分数

    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


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

分析:这道题初看起来第一感觉就是用暴力破解应该可以搞定,但是时间复杂度应该会相当可观,仔细观察,会发现这道题无非是全排列的一种运用,把等式定义为:

N=A+B/C ,则ABC组合在一起就是1到9的一个全排列,所以可以把问题转换成对于一个9位数的数字,如何将其划分为A、B、C三部分,使得其满足N=A+B/C(隐含条件:

B%C==0),对于一个9位数可以这样考虑:A是不可能大于N的,所以A的位数只可能是从1位到和N相同位数这个范围,确定了A的位数之后,剩下的就是B和C的总位数,

B数字的开始位置即A数字的下一位,C数字的最后一位就是整个9位数的最后一位,那如何确定B的结束位置呢?

这里有个小技巧,可以大大减少可能性的判断:

假设A的结束位置为 aEnd,则aEnd+1~9就是B和C的位置,在这个位置范围内,B最少占据了一半的数字,否则B/C就不能整除了,所以可以从aEnd+1~9的中间位置开始

确定B的结束位置,这时候可以从中间位置开始向后确定B的结束位置,一直到8的位置,确定了B的结束位置,则A、B、C三个数字的具体值就都可以确定了,判断是否符

合等式N=A+B/C,符合则输出。

以上确定B的结束位置的方法其实不怎么好,因为还是会浪费一些时间(自己模拟下就知道了),不过已经可以在规定的时间内得出答案了。

这里再介绍一种确定B结束位置的方法,可以让性能再提高一些:

观察等式:N=A+B/C,可以转换成==》B=(N-A)*C,N和A确定了(先确定A的结束位置后,再来确定B的结束位置的),C的最后一个数字确定了(整个9位数最后一位),即可以确定B最后一个数字了(这里将其定义为BL),这样可以从以上的aEnd+1~9的中间位置开始找,直到8,当数字为BL时,则判读是否符合等式:N=A+B/C,可以想想,其实这种等于BL的位置至多有一次(因为数字1到9不能重复出现),所以第一次找到和BL匹配的数字的时候就不用再往后找了。用这种方法,提高的性能还是非常可观的!

 According to :   http://blog.csdn.net/keepthinking_/article/details/8947014

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <time.h>
 4 
 5 int number, n = 0;
 6 int list[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
 7 
 8 int test;
 9 
10 void swap(int *a, int *b)
11 {
12     int temp = *a;
13     *a = *b;
14     *b = temp;
15 }
16 
17 int getNum(int s, int an)
18 {
19     int i, num = 0;
20     for (i = s; i <= an; i++)
21     {
22         num = list[i] + num * 10;
23     }
24     return num;
25 }
26 
27 void perm(int k, int m, int x)
28 {
29     int i, j, a, b, c;
30     
31     if (k > m)
32     {
33         for (i = 0; i < x; i++)
34         {
35             a = getNum(0, i);
36             test=((number-a)*list[8])%10;
37             for (j =i+(8-i)/2; j < 8; j++)
38             {
39                 if(list[j]==test)
40                 {
41                     b = getNum(i + 1, j);
42                     c = getNum(j + 1, 8);
43                     if (b % c == 0 && a + b / c == number)
44                     {
45                         n++;
46                     }
47                     break;
48                 }
49             }
50             
51         }
52         
53     }
54     else
55     {
56         for (i = k; i <= m; i++)
57         {
58             swap(&list[k], &list[i]);
59             perm(k + 1, m, x);
60             swap(&list[k], &list[i]);
61         }
62     }
63 }
64 
65 int main() 
66 {
67     clock_t s1, s2;
68     int temp, x;
69     while(scanf("%d", &number) != EOF && number != 0)
70     {
71         x = 0;
72         temp = number;
73         s1 = clock();
74         n = 0;
75         while (temp != 0) 
76         {
77             x++;
78             temp /= 10;
79         }
80         perm(0, 8, x);
81         printf("total:%d
", n);
82         s2 = clock();
83         printf("%f ms
", (double)(s2 - s1));
84     }
85 }
View Code
原文地址:https://www.cnblogs.com/zeze/p/daifenshu.html