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

1.带分数

问题描述:

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,b=(n-a)*c,用暴力求解就能求解出来。
因为共有9位数字可以用,所以c最大能取到四位数字,a最大能取到n-1。数字1~9分别出现且只出现一次(不包含0),用if语句即可筛选出来。

代码:

# encoding:utf-8
n=input()
#n=a+b/c b=(n-a)*c
count=0
for a in range(0,int(n)):
    for c in range(1,9999):
        b=(int(n)-int(a))*int(c)
        list1=list(str(a))+list(str(b))+list(str(c))
        if list1.count('1')==1 and list1.count('2')==1 and list1.count('3')==1 and list1.count('4')==1 and list1.count('5')==1 and list1.count('6')==1 and list1.count('7')==1 and list1.count('8')==1 and list1.count('9')==1 and list1.count('0')==0:
            count+=1
print(count)

参考链接: link.

2.李白打酒

问题描述:

话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。

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

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

解题思路:

使用递归求解,保证最后一次为花,且酒的数量为1。

代码:

# encoding:utf-8
res = 0
def dajiu(store,flower,wine):
	global res
    if store>0:
        dajiu(store-1,flower,wine*2)
    if flower>1:#最后一次为花
        dajiu(store,flower-1,wine-1)
    if (store==0 and flower==1 and wine==1):
        res += 1
    return res
print (dajiu(5,10,2))

运行结果:14

参考链接: link.

总结:

3.第39级台阶

问题描述:

小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!
站在台阶前,他突然又想着一个问题:
如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?

输出格式:
输出一个整数

解题思路:

使用递归,寻找登上39个台阶且步数为偶数的情况

代码:

# encoding:utf-8
def find(n, s):  #n代表阶梯数,s代表步数
    if n > 39:
        return 0
    elif n == 39 and s % 2 == 0:
        return 1
    return find(n + 1, s + 1) + find(n + 2, s + 1)

print(find(0,0))

运行结果:51167078

参考链接: link.

4.穿越雷区

问题描述:

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

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

数据格式要求:
输入第一行是一个整数n,表示方阵的大小, 4<=n<100
接下来是n行,每行有n个数据,可能是A,B,+,-中的某一个,中间用空格分开。
A,B都只出现一次。
要求输出一个整数,表示坦克从A区到B区的最少移动步数。
如果没有方案,则输出-1

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

则程序应该输出:
10
资源约定:
峰值内存消耗 < 512M
CPU消耗 < 1000ms

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

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程。

解题思路:

广度优先搜索

代码:

# encoding:utf-8
#穿越雷区
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)

参考链接:link.

5.迷宫

问题描述:

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

010000
000100
001001
110000

迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这 个它的上、下、左、右四个方向之一。 对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫, 一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。 对于下面这个更复杂的迷宫(30 行 50 列),请找出一种通过迷宫的方式, 其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。 请注意在字典序中D<L<R<U。(如果你把以下文字复制到文本文件中,请务 必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 maze.txt, 内容与下面的文本相同)

答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个字符串,包含四种字母 D、U、L、R,在提交答案时只填写这个字符串,填 写多余的内容将无法得分

解题思路:

这道题目可以采用深度优先搜索的方法,利用队列进行储存当前的位置,如果走到终点的话,队列就不再加入新东西。

代码:

# encoding:utf-8
from queue import Queue

maze = []
with open('maze.txt') as f:
    for line in f.readlines():
        maze.append(list(line.strip()))

m = len(maze)
n = len(maze[0])
visit = [[True]*n for _ in range(m)]

queue = Queue()
queue.put((0, 0, ''))
while queue:
    x, y, path = queue.get()
    if x == m - 1 and y == n - 1:# 走到终点结束
        print(path)
        break

    where = ['D', 'U', 'L', 'R']
    for i, (x1, y1) in enumerate([(1, 0), (-1, 0), (0, -1), (0, 1)]):
        new_x, new_y = x + x1, y+y1
        if 0<=new_x<m and 0<=new_y<n and maze[new_x][new_y] == '0' and visit[new_x][new_y]:
            queue.put((new_x, new_y, path+ where[i]))
            visit[new_x][new_y] = False

参考链接:link.

6.跳马

问题描述:

中国象棋半张棋盘如图1所示。马自左下角(0,0)向右上角(m,n)跳。规定只能往右跳,不准往左跳。比如图1中所示为一种跳行路线,并将路径总数打印出来。

输入格式:
只有一行:两个数n,m
输出格式:
只有一个数:总方案数total。

解题思路:

仔细想想马跳的情况就四种:右一上二,右一下二,右二上一,右二下一,而马的每一个位置都只有这四种跳法,求每一位置马的跳格最终就可跳到目标位置,所以用递归方法求解。

代码:

# encoding:utf-8
totle=0
def jump(r,c,a,b):#r,c表示马现在的位置,a,b分别表示马往右和往上跳几格
    global totle
    if(r<0 or r>m or c<0 or c>n):
        return
    if(r+a==m and c+b==n):#判断是否是解
        totle += 1
        return
        #马符合题目要求的四种跳法,在马的当前位置分别选择枚举这四种跳法会将所有情况枚举完
    jump(r+a,c+b,2,1)
    jump(r+a,c+b,-2,1)
    jump(r+a,c+b,1,2)
    jump(r+a,c+b,-1,2)

m,n = map(int,input().split())
jump(0,0,0,0)
print("%d"%totle)

参考链接:link.

7.路径之谜

问题描述:

小明冒充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

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms

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

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

解题思路:

这道题一看路线问题应该要使用dfs,我们使用反向思维,我们不断的拔剑,把剑拔完或者有一个为零而且到了就可以了。当到达终点时,除了要判断该点的坐标是不是终点坐标,或者判断所有的箭都已经拔完。

代码:

# encoding:utf-8
path = [0 for _ in range(401)]# 记录走过的点
dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]# 我们的移动
cntx = [0 for _ in range(21)]
cnty = [0 for _ in range(21)]# 记录箭的数量
maps = [[False for _ in range(21)]for _ in range(21)]# 用于判断是否走过
sun = False
tot = 0# 箭的总数

def check():# 判断是否完成,如果有一个为零,就不能往下走了
    for i in range(0, n):
        if cntx[i] != 0 or cnty[i] != 0:
            return False
    return True

def dfs(x, y, num):
    global sun
    path[num] = y *n + x # 坐标点
    maps[x][y] = True 
    cntx[x] -= 1 # 我们这步走过来拔剑
    cnty[y] -= 1 # 我们这步走过拔剑

    if x == n and y == n and check():
        sun = True# 完成走了
        return
    for i in range(4):
        x1 = x + dx[i]
        y1 = y + dy[i]
        if not sun and not maps[x1][y1] and 0 <= x1 < n and 0 <= y1 < n:
            if cntx[x1] > 0 and cnty[y1] > 0:
                dfs(x1, y1, num+1)
                maps[x1][y1] = False# 回溯,至关重要
                cntx[x1] += 1
                cnty[y1] += 1

n = int(input())
for i in range(0, n):
    cntx[i] = int(input())
    tot += cntx[i]
for i in range(0, n):
    cnty[i] = int(input())
    tot += cnty[i]
dfs(0, 0, 0)
print(path[:tot//2])# 走了箭的一半的数量应该没毛病

参考链接: link.

8.未名湖边的烦恼

问题描述:

问题描述
  每年冬天,北大未名湖上都是滑冰的好地方。北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩。
  每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个。现在的问题是,这些人有多少种排法,可以避免出现体育组没有冰鞋可租的尴尬场面。(两个同样需求的人(比如都是租鞋或都是还鞋)交换位置是同一种排法)
输入格式
  两个整数,表示m和n
输出格式
  一个整数,表示队伍的排法的方案数。
样例输入
3 2
样例输出
5
数据规模和约定
  m,n∈[0,18]

解题思路:

假设还鞋的都叫A,借鞋子的都叫B,拿题目给的3个人还,2个人借来说,就是A,B的排列组合,手动排出来如下:

AAABB
AABBA
ABABA
ABAAB
AABAB

一共是这五种。我们知道还鞋的必须大于等于借鞋的,即m>=n,我们假设一个递归函数fun_Rec(m, n),返回的是m人还鞋,n人借鞋 的排列数。一个人,要么借鞋要么还鞋。

这个队伍从后面开始看,甲可能是借鞋子的,也可能是还鞋的,所以
fun_Rec(3, 2)就有两种可能:fun_Rec(3, 1),fun_Rec(2, 2)
所以递归关系来了:
fun_Rec(m, n)=fun_Rec(m, n-1)+fun_Rec(m-1, n)
在m>=n的时候递归
在m<n的时候返回0
在n=0的时候(就是没有人借鞋子的时候,只有一种排法)返回1

代码:

#递归
# encoding:utf-8
def fun_Rec(m,n):   #m是还,n是借
	if n > m:
    	return 0
    elif n == 0:
        return 1
    else:
        return fun_Rec(m, n-1) + fun_Rec(m-1, n)

s = list(map(int, input().split()))
m, n = s[0], s[1]
print(fun_Rec(m, n))
#动态规划:dp[x][y] = dp[x][y-1] + dp[x-1][y]
# encoding:utf-8
s = list(map(int, input().split()))
m, n = s[0], s[1]
dp = [[0 for i in range(0, n+1)] for j in range(0, m+1)]
for i in range(1, m+1):
	dp[i][0] = 1     #把没有人借鞋子的那一列都置为1,因为没人借鞋子的时候只有一种排法
for x in range(1, m+1):
	for y in range(1, n+1):
    	if x >= y:
    		dp[x][y] = dp[x][y-1] + dp[x-1][y]
        else:
            continue
print(dp[m][n])

参考链接:link.

总结:

9.大臣的旅费

问题描述:

问题描述
很久以前,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
输出格式
大臣J从城市4到城市5要花费135的路费。

解题思路:

这道题的思考点在于随便找一个点,现在假设找到1这个点,从1这个点出发,找到距离1最远的点x,然后再从x这个点出发,再找到距离x最远的点,这个点就是大臣要走的最远距离。

代码:

# encoding:utf-8
cnt=0
node=0
def dfs(v,k):   #进行dfs搜索
    global cnt
    global node
    global vis
    if k>cnt:
        cnt=k
        node=v
    for i in range(len(E[v])):
        if vis[E[v][i][0]]==False: #没访问过的点都进行一次dfs
            vis[E[v][i][0]]=True #进行标记
            dfs(E[v][i][0],k+E[v][i][1])
            vis[E[v][i][0]]=False #回溯
n=int(input())
E=[[]for i in range(n+1)]
vis=[False for i in range(n+1)]
for i in range(n-1):
    x,y,z=map(int,input().split())
    E[x].append((y,z))
    E[y].append((x,z)) #将各个点进行连接,用列表数组的方式进行
vis[1]=True
dfs(1,0)  #找到距离1最远的点node
vis[1]=False
cnt=0
vis[node]=True
dfs(node,0)  #从node出发,找到最远的点,就是所要求的最远距离
res=0
for i in range(1,cnt+1):
    res+=i+10
print(res)

参考链接: link.

10.2n皇后问题

问题描述:

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

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

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

Sample Input
No.1
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1

No.2
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
Sample Output

No.1
2

No.2
0

解题思路:

n皇后问题:用回溯遍历所有情况。
判断下一位置是否合理。
设置递归出口,第n行安全。此时cnt+1。继续回溯遍历找到所有解。

2n皇后问题:
一种皇后放完后怎么保存这种皇后对下一种皇后的影响?
回溯只有要考虑上一种皇后,回溯是不是有点复杂?

因为要求得所有解,所以必须遍历所有情况,所以横向循环,纵向递归,遍历了所有的情况,没有用到回溯。
里面d存储的是前面已经存储好的黑皇后的location,就像n皇后问题一样。然后每一次递归列数从0开始,将这一列的所有情况遍历完,当该行有位置是合理的,就从此处生成一个递归分支,由此就可以遍历所有情况。

代码:

# encoding:utf-8
cnt = 0

def issafe(d, row):
    for i in range(row):
        if d[i] == d[row] or abs(i - row) == abs(d[i] - d[row]):
            return False
    return True


def blackDfs(c, d, n, row):
    global cnt                            #已经放置了n个白皇后,放置了n个黑皇后则计数
    if row == n:
        cnt += 1
        return
    d[row] = 0

    while d[row] < n:
        if c[row][d[row]] == 1 and issafe( d, row):
            blackDfs(c, d, n, row + 1)
        d[row] += 1


def dfs(a, b, n, row):
    if row == n:
        c = [[0 for i in range(n)] for i in range(n)]
        for i in range(n):
            for j in range(n):
                c[i][j] = a[i][j]  # save a to c

        for i in range(n):
            c[i][b[i]] = 0

        d = [0 for i in range(n)]
        blackDfs(c, d, n, 0)
        return

    b[row] = 0
    while b[row] < n:
        if a[row][b[row]] == 1 and issafe(b, row):
            dfs(a, b, n, row + 1)
        b[row] += 1


def main():
    n = int(input())

    a = [[0 for i in range(n)] for i in range(n)]
    b = [0 for i in range(n)]

    for i in range(n):
        tmp = input().split()
        tmp=list(map(int,tmp))
        a[i]=tmp
    dfs(a, b, n, 0)
    print(cnt)


if __name__ == '__main__':
    main(

参考链接:link.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值