【蓝桥杯】 历届试题 带分数(全排列)—— 酱懵静

历届试题 带分数

问题描述
100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
还可以表示为:100 = 82 + 3546 / 197。
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。

输入格式:从标准输入读入一个正整数N (N<1000*1000)
输出格式:程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!

样例输入:100
样例输出:11

样例输入:105
样例输出:6



---分割线---



分析:
本题给人的第一感觉是,枚举呗~
确实,对于任意的输入,总可以通过枚举来进行判断
但是对于枚举而言,势必需要考虑其枚举范围
先来看一下本题提供的式子:N = a + b / c
假设题目输入的N=100,那么a的枚举范围就是1-99,对于后面的b / c的范围相较而言就要大很多。因为剩下的项是由一个除法式子组成的,而这里面的两个数的排列情况又是庞大的。并且最恐怖的是,后面的b / c这一部分还会随着a的变化又重新组合,于是乎~~~陷入困难

这时候必须另辟捷径了
熟话说的好,失败乃成功之母
在上面的分析中,我相信同学们应该都注意到了一个点
那就是,无论你的N是多少,在你的枚举过程中,总是会重头到尾的去把可能的情况枚举一遍。并且为了便于枚举,总是会按照某种逻辑来进行(当然,这个情况下我相信大部分同学都是依照全排列的顺序来进行的)。
既然如此,反正对于任何的输入(N),都会去走一遍那个排列的过程,那么为什么我们不把这些枚举情况都保存下来呢?(类似于打表)

话说到这里,相信你也或多或少有一些思路了
是的,我们的解题思路就是从这里下手:
将1-9进行全排列,然后从中间按照某种顺序截取三段,以这三段分别作为a、b、c,接着带入那个公式,并将得到的结果保存在某个数组中( cnt[ a+b/c ]++ ),最后利用数组的随机访问特性直接输出结果即可(即假设给出下面某种排列:123|4567|89,则你可以在这串数中任意插入两根棍子,将其分成三部分)。

分析到这里,还不够,为了确保时间上的可行,我们还要分析一下程序大概的枚举次数
要知道 9!=362,880 ,而对于每一个排列的结果又有C上3下8(组合数C3\8=56)种情况,这样一来,总的枚举情况就有 362,880╳56=20,316,800,约两千万的次数

还能接受
but,实际上对于这里每一个枚举,我们的“插棍子”也是通过三个循环来实现的(看了代码部分会更清楚这个实现),因此实际上程序的赋值语句可能都达到了两千万╳10=两亿左右的次数

前面说了,我们是在打表
也就是说上面的代码执行结束后,会生成一个记录每个数的带分数的数量的数组
这样,对于后面的任何输出都可以直接将其带分数数量输出
这样也就不用担心超时了

下面给出本题的完整代码:


---分割线---


#include<iostream>
#include<algorithm>
using namespace std;

int p[9];							//用于放置基本的9个数字
int cnt[10000005];					//打表用到的数组

int main()
{
    for(int i=0;i<9;i++)
        p[i]=i+1;
    int a,b,c,ans;
    do{
        for(int i=0;i<=6;i++)
            for(int j=i+1;j<=7;j++)
            {
            	a=b=c=ans=0;
                for(int k=0;k<=i;k++)
                {
                    a=a*10+p[k];
                }
                for(int k=i+1;k<=j;k++)
                {
                    b=b*10+p[k];
				}
                for(int k=j+1;k<=8;k++)
                {
                    c=c*10+p[k];
                }
                if(b%c==0)
                {
                    ans=a+b/c;
                    if(ans<1000000)
                    cnt[ans]++;
                }
            }
    }while(next_permutation(p,p+9));  //这是一个求一个排序的下一个排列的函数,可以遍历全排列,要包含头文件<algorithm>
    int n;
    cin>>n;
    cout<<cnt[n];    
}

发布了30 篇原创文章 · 获赞 67 · 访问量 3052

猜你喜欢

转载自blog.csdn.net/the_ZED/article/details/100145667