Python蓝桥杯练习 带分数

问题描述

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

输入格式

从标准输入读入一个正整数N (N<1000*1000)

输出格式

程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!

样例输入1

100

样例输出1

11

样例输入2

105

样例输出2

6

思路

这里的拆分形式可以表达为:N=A+B/C
而A、B、C中,1~9的数字在这三个数中汇总起来只会出现一次
注意是1~9出现且仅出现一次!!!
A、B、C之间是有关系的

  • 对A而言他是一个在1N-1(因为是19而不是0~9)之间的数
  • B可以改写为(N-A)*C
  • B是可以整除C的
  • B是可以整除(N-A)的
  • 1~9在他们之中出现且仅出现一次
  • 注意ABC中不能有重复数字

那么可以先遍历A,得到一个数字M=N-A
比如说
N=100,遍历到A=3,那么M=97
B=M*C,即B=97*C
此时A是一位数字3,那么其他8位数字是可能出现在B和C之中,B又需要大于C,所以B的位数应该大于等于C,那么B至少应该是4位数字,反过来说C至多是4位数字
那么我们用B的所有排列,利用排列8个中选4个,8个中选5个,8个中选6个,8个中选7个,得到所有B的可能,此时B是可以整除C得到97的,那么反过来B可以整除97得到C的,那么首先判断B的候选数是否可以整除M(在这里是97),如果可以,那么相除得到C,判断得到的C是否出现和B或者和A相同的数字,如果没有,那么这一组数字便是需要的A、B、C,否则继续遍历

实现

遍历A从1到N-1,得到M=N-A
计算A所占的位数
那么B的位数是 (9-A所占位数)/2~9-A所占位数-1
C的位数是 9-A所占位数-B所占位数
遍历B的值,对A中剩余未出现的数字,取B所有可能出现的位数的排列,判断B%M==0,如果是,那么判断整除得到的C的位数是否正确,C中的数字是否与1~9中除了AB出现过的数字一一对应,如果一一对应,那么是一个可能解,否则继续循环

判断是否一一对应

可以先转换为集合,再使用python中的集合方法判断两个集合元素是否相同

排列的实现

利用递归,取返回从下标a到下标b的n个排列,在函数中,遍历将原数组中下标a与下标a+i位置的数调换,调用取从下标a+1到下标b的n-1个排列,与下标a组合,这样就可以得到排列


排列
组合的实现

如果需要得到组合,依然可以利用递归,取返回从下标a到下标b的n个组合,在函数中,遍历将原数组中下标a与下标a+i位置的数调换,注意这里是调用取从下标a+i+1到下标b的n-1个排列,与下标a+i组合,得到组合


组合(注意和排列的不同)

Python源代码(未剪枝,自然超时了,只有33分)

import math

N=int(input())
count=0

def get_outset(num_set,standard_set):
    # 得到standard列表中num_set没有出现的部分
    out_set=[]
    for i in standard_set:
        if(i not in num_set):
            out_set.append(i)
    return out_set

def judge(perm,M,num_set):
    global count
    B = int("".join(perm))
    if (B % M == 0):
        out_set_C = get_outset(str(B), "".join(num_set))
        C = list(str(int(B / M)))
        flag = 1
        if(len(C)==len(out_set_C)):
            for alpha in C:
                if (alpha not in out_set_C):
                    flag = 0
                    break
            set_C=set(C)
            if(len(C)!=len(set_C)):
                flag=0
            if (flag == 0):
                return
            else:
                count += 1

def get_permutation(num_set,a,b,num,M):
    # 求排列
    if(num==0):
        # 这里已经得到了B对应的排列,进行检测
        perm=num_set[0:a]
        judge(perm,M,num_set)
        return

    for i in range(a,b):
        copy_set=num_set[::]
        copy_set[a],copy_set[i]=copy_set[i],copy_set[a]     # swap
        get_permutation(copy_set,a+1,b,num-1,M)


for A in range(1,N):
    M=N-A
    if('0' in str(A)):
        continue
    if(len(str(A))!=len(set(list(str(A))))):
        continue
    out_set=get_outset(str(A),"123456789")
    min_length_B= math.ceil((9-len(str(A)))/2)
    max_length_B=9-len(str(A))
    for num in range(min_length_B,max_length_B):
        get_permutation(out_set,0,len(out_set),num,M)

print(count)

剪枝(66分)慢慢剪

用C的排列,B=M*C,判断B的数字是否符合规则

import math

N=int(input())
count=0

def get_outset(num_set,standard_set):
    # 得到standard列表中num_set没有出现的部分
    out_set=[]
    for i in standard_set:
        if(i not in num_set):
            out_set.append(i)
    return out_set

def judge(perm,M,num_set):
    global count
    C = int("".join(perm))
    B= M * C
    if(C>B):
        return

    out_set_B = get_outset(str(C), "".join(num_set))
    flag = 1
    if(len(str(B))==len(out_set_B)):
        if (len(str(B)) == len(set(list(str(B))))):
            for alpha in str(B):
                if (alpha not in out_set_B):
                    flag = 0
                    break
            if (flag == 0):
                return
            else:
                count += 1

def get_permutation(num_set,a,b,num,M):
    # 求排列
    if(num==0):
        # 这里已经得到了C对应的排列,进行检测
        perm=num_set[0:a]
        judge(perm,M,num_set)
        return

    for i in range(a,b):
        copy_set=num_set[::]
        copy_set[a],copy_set[i]=copy_set[i],copy_set[a]     # swap
        get_permutation(copy_set,a+1,b,num-1,M)


for A in range(1,N):
    M=N-A
    if('0' in str(A)):
        continue
    if(len(str(A))!=len(set(list(str(A))))):
        continue
    out_set=get_outset(str(A),"123456789")
    max_length_C= math.ceil((9-len(str(A)))/2)
    min_length_C= 1
    for num in range(min_length_C,max_length_C):
        get_permutation(out_set,0,len(out_set),num,M)




print(count)



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容