蓝桥杯python小学组_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组合,这样就可以得到排列

1240

组合的实现

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

1240

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值