【思特奇杯·云上蓝桥-算法集训营】第2周

带分数


问题描述
100 可以表示为带分数的形式:100 = 3 + 69258 / 714。

还可以表示为:100 = 82 + 3546 / 197。

注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。

类似这样的带分数,10011 种表示法。

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

输出格式
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。

注意:不要求输出每个表示,只统计有多少表示法!

样例输入1
100
样例输出1
11
样例输入2
105
样例输出2
6

from itertools import permutations

num = int(input())
ans = 0
for n in range(1, num+1):
    if '0' in str(n) or len(set(list(str(n)))) != len(str(n)):
        # 判断是否有0和重复数字
        continue

    diff = num - n # 剩下的数(后面的分数应该算出来的值)
    s = '123456789'
    for i in str(n):
        s = s.replace(i, '') # 去掉已经使用过的数

    for length in range(1, len(s)//2 + 1): # 分母的长度
        for i in permutations(s, length): # 长度为length的分母的全排列
            fenzi = str(int(''.join(i)) * diff) # 计算分子
            if len(fenzi) == len(s) - length: # 判断计算出来的分子是否合法
                if set(list(fenzi)) == set(list(s)) - set(list(''.join(i))):
                    ans += 1
            
print(ans)

李白打酒


问题描述

话说大诗人李白,一生好饮。幸好他从不开车。

一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:

无事街上走,提壶去打酒。

逢店加一倍,遇花喝一斗。

这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。

请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。

def fun(a, b, c):
    cnt = 0
    if a == 0 and b == 1 and c == 1:
        cnt += 1
    if a > 0:  # 还有酒店
        cnt += fun(a-1, b, c*2)  # 酒加倍
    if b > 0:  # 还有花店
        cnt += fun(a, b-1, c-1)  # 酒减一
    return cnt
a = fun(5,10,2)
print(a)

第39级台阶

题目描述:

小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!

站在台阶前,他突然又想着一个问题:

如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?

输出格式:

输出一个整数

num = 0
def recu(step,n):
    global num
    if n > 39:
        return
    if n == 39 and step % 2 == 0:
        num += 1
        return
    recu(step+1,n+1)
    recu(step+1,n+2)
recu(0,0)
print(num)

穿越雷区

问题描述

X星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废。
某坦克需要从A区到B区去(A,B区本身是安全区,没有正能量或负能量特征),怎样走才能路径最短?

已知的地图是一个方阵,上面用字母标出了A,B区,其它区都标了正号或负号分别表示正负能量辐射区。
例如:
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -

坦克车只能水平或垂直方向上移动到相邻的区。

数据格式要求:

输入第一行是一个整数n,表示方阵的大小, 4<=n<100
接下来是n行,每行有n个数据,可能是A,B,+-中的某一个,中间用空格分开。
A,B都只出现一次。

要求输出一个整数,表示坦克从A区到B区的最少移动步数。
如果没有方案,则输出-1

例如:
用户输入:
5
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -

则程序应该输出:
10

n = int(input())

m = [input().split(' ') for _ in range(n)]

visit = [[False] * n for _ in range(n)] # 记录是否访问过

step = [(0, -1), (0, 1), (-1, 0), (1, 0)]

queue = [(0, 0, 0)] # 存三个值:坐标、当前移动的步数

while queue:
    y, x, t = queue.pop(0)
    if m[y][x] == 'B':
        print(t)
        break
    for dy, dx in step:
        ny = y + dy
        nx = x + dx
        if -1 < nx < n and -1 < ny < n:
            if not visit[ny][nx] and m[y][x] != m[ny][nx]:
            	# 没有访问过并且不是连续走相同的区域
                queue.append((ny, nx, t+1))
                visit[y][x] = True
    
if not queue:
    print(-1)

迷宫


问题描述

下图给出了一个迷宫的平面图,其中标记为 1 的为障碍,标记为 0 的为可以通行的地方。

010000
000100
001001
110000

迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这 个它的上、下、左、右四个方向之一。

对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫,一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。

对于下面这个更复杂的迷宫(3050 列),请找出一种通过迷宫的方式, 其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。 请注意在字典序中D<L<R<U。(如果你把以下文字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 maze.txt,内容与下面的文本相同)


m = '''01010101001011001001010110010110100100001000101010
00001000100000101010010000100000001001100110100101
01111011010010001000001101001011100011000000010000
01000000001010100011010000101000001010101011001011
00011111000000101000010010100010100000101100000000
11001000110101000010101100011010011010101011110111
00011011010101001001001010000001000101001110000000
10100000101000100110101010111110011000010000111010
00111000001010100001100010000001000101001100001001
11000110100001110010001001010101010101010001101000
00010000100100000101001010101110100010101010000101
11100100101001001000010000010101010100100100010100
00000010000000101011001111010001100000101010100011
10101010011100001000011000010110011110110100001000
10101010100001101010100101000010100000111011101001
10000000101100010000101100101101001011100000000100
10101001000000010100100001000100000100011110101001
00101001010101101001010100011010101101110000110101
11001010000100001100000010100101000001000111000010
00001000110000110101101000000100101001001000011101
10100101000101000000001110110010110101101010100001
00101000010000110101010000100010001001000100010101
10100001000110010001000010101001010101011111010010
00000100101000000110010100101001000001000000000010
11010000001001110111001001000011101001011011101000
00000110100010001000100000001000011101000000110011
10101000101000100010001111100010101001010000001000
10000010100101001010110000000100101010001011101000
00111100001000010000000110111000000001000000001011
10000001100111010111010001000110111010101101111000'''

m = m.split('\n')

visit = [[False] * 50 for _ in range(30)]
visit[0][0] = True

step = [(1, 0, 'D'), (0, -1, 'L'), (0, 1, 'R'), (-1, 0, 'U')]


queue = [(0, 0, -1, 0)] # 坐标、父节点在path中的下标、走的方向对应的字母
path = []
while queue:
    y, x, _, _  = cur = queue.pop(0)
    path.append(cur)

    if cur[:2] == (29, 49):
        # 走到终点
        temp = []
        i = len(path) - 1
        while i > 0: # 沿着之前标记的父节点将路径取出
            temp.append(path[i][3])
            i = path[i][2]
        temp.reverse() # 反转,因为取出来的路径是反的
        print(''.join(temp))
        break

    for dy, dx, dir in step: # 往上下左右走一步
        ny, nx = y+dy, x+dx # 下一步到达的位置
        if -1 < nx < 50  and -1 < ny < 30 and m[ny][nx] == '0' and not visit[ny][nx]:
            # 判断是否越界、迷宫该位置是否能走、是否已经走过
            queue.append((ny, nx, len(path)-1, dir)) # 将下一步添加到队列中,len(path)-1 是添加到节点的父节点在path中的下标
            visit[ny][nx] = True # 标记已经访问过


跳马


问题描述

一个8×8的棋盘上有一个马初始位置为(a,b),他想跳到(c,d),问是否可以?如果可以,最少要跳几步?

输入格式
一行四个数字a,b,c,d。

输出格式
  如果跳不到,输出-1;否则输出最少跳到的步数。

样例输入
1 1 2 3

样例输出
1
a, b, c, d = map(int, input().split(' '))

step = [(1, 2), (1, -2), (-1, 2), (-1, -2), (2, 1), (2, -1), (-2, 1), (-2, -1)]

visit = [[False]*8 for _ in range(8)]


queue = [(a, b, 0)] # 坐标、步数

while queue:
    y, x, t = queue.pop(0)

    if y == c and x == d:
        print(t)
        break

    for dy, dx in step:
        ny = y + dy
        nx = x + dx
        if -1 < ny < 8 and -1 < nx < 8 and not visit[ny][nx]:
            queue.append((ny, nx, t+1))
            visit[ny][nx] = True
    
if not queue:
    print(-1)


路径之谜

小明冒充X星球的骑士,进入了一个奇怪的城堡。

城堡里边什么都没有,只有方形石头铺成的地面。

假设城堡地面是 n x n 个方格。【如图1.png】所示。

按习俗,骑士要从西北角走到东南角。
可以横向或纵向移动,但不能斜着走,也不能跳跃。
每走到一个新方格,就要向正北方和正西方各射一箭。
(城堡的西墙和北墙内各有 n 个靶子)

同一个方格只允许经过一次。但不必走完所有的方格。

如果只给出靶子上箭的数目,你能推断出骑士的行走路线吗?

有时是可以的,比如图1.png中的例子。

本题的要求就是已知箭靶数字,求骑士的行走路径(测试数据保证路径唯一)

输入
第一行一个整数N(0<N<20),表示地面有 N x N 个方格
第二行N个整数,空格分开,表示北边的箭靶上的数字(自西向东)
第三行N个整数,空格分开,表示西边的箭靶上的数字(自北向南)

输出
一行若干个整数,表示骑士路径。

为了方便表示,我们约定每个小格子用一个数字代表,从西北角开始编号: 0,1,2,3…
比如,图1.png中的方块编号为:

0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15

样例输入
4
2 4 3 4
4 3 3 3
样例输出
0 4 5 1 2 3 7 11 10 9 13 14 15

n = int(input())

nums = [list(map(int, input().split(' '))) for _ in range(2)] # 第一行是上面的,第二行是左面的

visit = [[False]*n for _ in range(n)]
visit[0][0] = True

ans = [0]

record = [[0]*n for _ in range(2)]
record[0][0] = record[1][0] = 1

step = [(0, -1), (0, 1), (-1, 0), (1, 0)]

def dfs(y, x):
    if y == n-1 and x == n-1 and record == nums:
        print(' '.join(map(str, ans)))
        return
    for dy, dx in step:
        ny = y + dy
        nx = x + dx
        if -1 < ny < n and -1 < nx < n and not visit[ny][nx]:
            ans.append(ny*n + nx)
            visit[ny][nx] = True
            record[0][nx] += 1
            record[1][ny] += 1

            dfs(ny, nx)

            ans.pop()
            visit[ny][nx] = False
            record[0][nx] -= 1
            record[1][ny] -= 1
            
dfs(0, 0)

未名湖边的烦恼


问题描述
  每年冬天,北大未名湖上都是滑冰的好地方。北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩。
每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个。现在的问题是,这些人有多少种排法,可以避免出现体育组没有冰鞋可租的尴尬场面。(两个同样需求的人(比如都是租鞋或都是还鞋)交换位置是同一种排法)

输入格式
两个整数,表示m和n

输出格式
一个整数,表示队伍的排法的方案数。

样例输入
3 2

样例输出
5

m, n = map(int, input().split(' '))

record = [[-1]*(n+1) for _ in range(m+1)]

def dfs(a, b): # 还鞋、借鞋
    if a == b == 0:
        return 1
    
    if record[a][b] != -1:
        ans = record[a][b]
    else:
        ans = 0
        if a > 0:
            ans += dfs(a-1, b)
        if 0 < b <= a:
            ans += dfs(a, b-1)
        record[a][b] = ans
    
    return ans

print(dfs(m, n))


大臣的旅费


问题描述
很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。

为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。

J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。

聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。

J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?

输入格式
输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数

城市从1开始依次编号,1号城市为首都。

接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)

每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。

输出格式
输出一个整数,表示大臣J最多花费的路费是多少。

样例输入1
5
1 2 2
1 3 1
2 4 5
2 5 4
样例输出1
135

n = int(input())
lis = [list(map(int, input().split(' '))) for _ in range(n-1)]
m = {i: [] for i in range(1, n+1)}
for i in lis:
    m[i[0]].append(i[1:])
    m[i[1]].append((i[0], i[2]))

visit = [False] * (n+1)

node = max_length = 0
def dfs(x, length):
    global max_length
    if length > max_length:
        global node
        max_length, node = length, x
    
    for nx, l in m[x]:
        if not visit[nx]:
            visit[nx] = True
            dfs(nx, length+l)
            visit[nx] = False

dfs(1, 0)

visit = [False] * (n+1)
visit[node] = True
dfs(node, 0)


print(max_length * 11 + max_length*(max_length-1)//2)

2n皇后问题


问题描述
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。

输入格式
  输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个01的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。

输出格式
输出一个整数,表示总共有多少种放法。

样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1

样例输出
2
样例输入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1

样例输出
0

def check(record, i, j):
    # 根据之前已有的,判断第i行第j列可不可以放
    for k in range(i): # 遍历前面所有的行,k:之前某一行
        if j == record[k] or abs(record[k] - j) == abs(i - k):
            return False
    return True
    

def dfs(record, i, color):
    if i == n: # 到达最后一行,也就是说所有皇后都可以摆上
        if color == 'black':
            dfs([0]*n, 0, 'white')
        else:
            global ans
            ans += 1
        return

    for j in range(n):
        # 检查当前第i行的皇后放在第j列是否合法
        if m[i][j] == '1':
            if check(record, i, j):
                m[i][j] = '2'
                record[i] = j
                dfs(record, i+1, color)
                m[i][j] = '1'
            

n = int(input())
m = [input().split(' ') for _ in range(n)]

ans = 0
dfs([0]*n, 0, 'black')

print(ans)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值