当前位置:   article > 正文

蓝桥杯刷题总结---第六周_一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油条是空的)

一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油条是空的)

一.旅行家的预算

一个旅行家想驾驶汽车以最少的费用从一个城市  到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离D1、汽车油箱的容量C(以升为单位)、每升汽油能行驶的距离D2、出发点每升汽油价格P  和沿途油站数N(N可以为零),油站i离出发点的距离Di、每升汽油价格Pi(i=1,2,……N)。计算结果四舍五入至小数点后两位。如果无法到达目的  地,则输出“No  Solution”。

思路:使用贪婪策略,对每一个结点分析,若存在比当前结点小且可以到达的结点则停车补油,若不存在则在可到达范围内选择一个油价最小的站点补油,并且需要将原来的油用完.

  1. D1,C,D2,P,N=map(eval,input().strip().split())
  2. station=[list(map(eval,input().strip().split()))for i in range(N)]
  3. fmax=0
  4. fmin=0
  5. ans=0
  6. now=0
  7. now_station=-1
  8. max_dis=C*D2
  9. while len(station):
  10. flag=True
  11. fmax=fmin
  12. while fmin<len(station) and fmax<len(station) and now+max_dis>=station[fmax][0]:
  13. flag=False
  14. if now_station==-1 and station[fmax][1]<=P:
  15. fmin=fmax
  16. break
  17. if now_station>=0 and station[fmax][1]<=station[now_station][1]:
  18. fmin=fmax
  19. break
  20. if station[fmin][1]>=station[fmax][1]:
  21. fmin=fmax
  22. fmax+=1
  23. if flag:
  24. if now_station==len(station)-1 and now+max_dis>=D1:
  25. ans+=station[now_station][1]*(D1-now)
  26. print("{:.2f}".format(ans / D2))
  27. break
  28. print("No Solution")
  29. break
  30. if now_station<0:
  31. if P<station[fmin][1]:
  32. if max_dis>=D1:
  33. ans+=P*D1
  34. print("{:.2f}".format(ans / D2))
  35. break
  36. now+=max_dis
  37. ans+=max_dis*P
  38. else:
  39. now+=station[fmin][0]
  40. ans+=now*P
  41. now_station=fmin
  42. else:
  43. if station[now_station][1]<station[fmin][1]:
  44. if now+max_dis<=D1:
  45. now+=max_dis
  46. ans+=max_dis*station[now_station][1]
  47. else:
  48. ans+=(D1-now)*station[now_station][1]
  49. now=D1
  50. print("{:.2f}".format(ans/D2))
  51. break
  52. else:
  53. ans+=(station[fmin][0]-now)*station[fmin][1]
  54. now=station[fmin][0]
  55. now_station=fmin
  56. fmin+=1
  57. if N==0:
  58. if max_dis>=D1:
  59. print("{:.2f}".format(D1*P/D2))
  60. else:
  61. print("No Solution")

二.星际交流

人类终于登上了火星的土地并且见到了神秘的火  星人。人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法。这种交流方法是这样  的,首先,火星人把一个非常大的数字告诉人类科学家,科学家破解这个数字的含义后,再把一个很小的数字加到这个大数上面,把结果告诉火星人,作为人类的回  答。
火星人用一种非常简单的方式来表示数字——掰手指。火星人只有一只手,但这只手上有成千上万的手指,这些手指排成一列,分别编号为1,2,3……。火星人的任意两根手指都能随意交换位置,他们就是通过这方法计数的。
一个火星人用一个人类的手演示了如何用手指计数。如果把五根手指——拇指、食指、中指、无名指和小指分别编号为1,2,3,4和5,当它们按正常顺序  排列  时,形成了5位数12345,当你交换无名指和小指的位置时,会形成5位数12354,当你把五个手指的顺序完全颠倒时,会形成54321,在所有能够形  成的120个5位数中,12345最小,它表示1;12354第二小,它表示2;54321最大,它表示120。下表展示了只有3根手指时能够形成的6个  3位数和它们代表的数字:
三进制数
123
132
213
231
312
321
代表的数字
1
2
3
4
5
6
现在你有幸成为了第一个和火星人交流的地球人。一个火星人会让你看他的手指,科学家会告诉你要加上去的很小的数。你的任务是,把火星人用手指表示的数  与科  学家告诉你的数相加,并根据相加的结果改变火星人手指的排列顺序。输入数据保证这个结果不会超出火星人手指能表示的范围。

思路:使用全排列,但是C语言的next_permutation和python里的itertools里面的permutation的排列结果不相同,需要用python重新构造一个排列函数

  1. def next_permutation(a):
  2. """Generate the lexicographically next permutation inplace.
  3. https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
  4. Return false if there is no next permutation.
  5. """
  6. # Find the largest index i such that a[i] < a[i + 1]. If no such
  7. # index exists, the permutation is the last permutation
  8. for i in reversed(range(len(a) - 1)):
  9. if a[i] < a[i + 1]:
  10. break # found
  11. else: # no break: not found
  12. return False # no next permutation
  13. # Find the largest index j greater than i such that a[i] < a[j]
  14. j = next(j for j in reversed(range(i + 1, len(a))) if a[i] < a[j])
  15. # Swap the value of a[i] with that of a[j]
  16. a[i], a[j] = a[j], a[i]
  17. # Reverse sequence from a[i + 1] up to and including the final element a[n]
  18. a[i + 1:] = reversed(a[i + 1:])
  19. return True
  20. N=int(input().strip())
  21. M=int(input().strip())
  22. nums=list(map(int,input().strip().split()))
  23. for _ in range(M):
  24. next_permutation(nums)
  25. for i in nums:
  26. print(i,end=' ')

三.连续正整数和

78这个数可以表示为连续正整数的和,1+2+3,18+19+20+21,25+26+27。

思路:使用高斯求和

  1. num=int(input())
  2. for n in range(1,num//2+1):
  3. for m in range(n+1,num//2+2):
  4. if (n+m)*(m-n+1)==2*num:
  5. print(n,m)
  6. elif (n+m)*(m-n+1)>2*num:
  7. break

四.log大侠

 atm参加了速算训练班,经过刻苦修炼,对以2为底的对数算得飞快,人称Log大侠。
  一天,Log大侠的好友 drd 有一些整数序列需要变换,Log大侠正好施展法力...
变换的规则是: 对其某个子序列的每个整数变为: [log_2 (x) + 1]  其中 [] 表示向下取整,就是对每个数字求以2为底的对数,然后取下整。
例如对序列 3 4 2 操作一次后,这个序列会变成 2 3 2。
 drd需要知道,每次这样操作后,序列的和是多少。

  1. from math import *
  2. n,m=map(int,input().split())
  3. def log_2(num):
  4. return int(log(num,2)+1)
  5. nums=list(map(int,input().split()))
  6. area=[list(map(int,input().split())) for i in range(m)]
  7. for L,R in area:
  8. for i in range(L-1,R):
  9. nums[i]=log_2(nums[i])
  10. print(sum(nums))

五.排列序数

 如果用a b c d这4个字母组成一个串,有4!=24种,如果把它们排个序,每个串都对应一个序号:
  abcd  0
  abdc  1
  acbd  2
  acdb  3
  adbc  4
  adcb  5
  bacd  6
  badc  7
  bcad  8
  bcda  9
  bdac  10
  bdca  11
  cabd  12
  cadb  13
  cbad  14
  cbda  15
  cdab  16
  cdba  17
  ...
 现在有不多于10个两两不同的小写字母,给出它们组成的串,你能求出该串在所有排列中的序号吗?

思路:使用全排列函数,但是这里可以使用python自带的全排列函数,自己构建则会超时

  1. import itertools
  2. n = input()
  3. x = sorted(n)
  4. ans=0
  5. for i in itertools.permutations(x):
  6. if i==tuple(n):
  7. print(ans)
  8. break
  9. ans+=1

六.重复模式

作为 drd 的好朋友,技术男 atm 在 drd 生日时送给他一个超长字符串 S 。atm 要 drd 在其中找出一个最长的字符串 T ,使得 T 在 S 中至少出现了两次,而他想说的秘密就藏在 T 中。 

 由于字符串实在是太长了,drd 总是找不到合适的 T 。于是 drd 请你帮他找到这个 T 的长度。

思路:贪婪策略,从最大的长度开始判断,创建字典保存每一个长度被遍历过的字符串,如果字典不为0,则说明之前出现过

  1. from collections import defaultdict
  2. s=input()
  3. n=len(s)-1
  4. flag=True
  5. while n>0 and flag:
  6. d=defaultdict(int)
  7. for i in range(len(s)-n+1):
  8. if d[s[i:i+n]]==0:
  9. d[s[i:i+n]]=1
  10. else:
  11. print(n)
  12. flag=False
  13. break
  14. n-=1

七.秘文搜索


福尔摩斯从X星收到一份资料,全部是小写字母组成。
他的助手提供了另一份资料:许多长度为8的密码列表。
福尔摩斯发现,这些密码是被打乱后隐藏在先前那份资料中的。
请你编写一个程序,从第一份资料中搜索可能隐藏密码的位置。要考虑密码的所有排列可能性。

思路:不用直接全排列,我们使用字典保存密文中所有字母出现的次数,再遍历资料中所有长度为8的子串即可.

  1. from collections import defaultdict
  2. text=input().strip()
  3. n=int(input().strip())
  4. ans=0
  5. mima=[input().strip() for i in range(n)]
  6. def num_in (ss):
  7. d=defaultdict(int)
  8. for i in ss:
  9. d[i]+=1
  10. return d
  11. text_key=[num_in(text[i:i+8]) for i in range(len(text)-7)]
  12. for i in text_key:
  13. for j in mima:
  14. temp_d=num_in(j)
  15. flag=True
  16. for jj in j:
  17. if temp_d[jj]!=i[jj]:
  18. flag=False
  19. break
  20. if flag:
  21. ans+=1
  22. print(ans)

八.邮票

给定一个信封,有N(1≤N≤100)个位置可以贴邮票,每个位置只能贴一张邮票。我们现在有M(M< =100)种不同邮资的邮票,面值为X1,X2….Xm分(Xi是整数,1≤Xi≤255),每种都有N张。
显然,信封上能贴的邮资最小值是min(X1,  X2,  …,  Xm),最大值是  N*max(X1,  X2,  …,  Xm)。由所有贴法得到的邮资值可形成一个集合(集合中没有重复数值),要求求出这个集合中是否存在从1到某个值的连续邮资序列,输出这个序列的  最大值。
例如,N=4,M=2,面值分别为4分,1分,于是形成1,2,3,4,5,6,7,8,9,10,12,13,16的序列,而从1开始的连续邮资序列为1,2,3,4,5,6,7,8,9,10,所以连续邮资序列的最大值为10分。

思路:使用dfs记忆递归加剪枝回溯,flags[num][0]记录总面值为num是否被访问过,flags[num][1]记录总面值为n需要的牌数,将牌从大到小排序,如果有总牌数已经被达到并且数量比目前的n少,则剪枝

  1. N=int(input().strip())
  2. M=int(input().strip())
  3. stamp=list(map(int,input().strip().split()))
  4. stamp.sort(reverse=True)
  5. def dfs(num_sum,n):
  6. global N,M,stamp,flags
  7. if n>N:
  8. return
  9. if flags[num_sum][0]==1 and flags[num_sum][1]<=n:
  10. return
  11. else:
  12. # print(num_sum)
  13. flags[num_sum][0]=1
  14. flags[num_sum][1]=n
  15. for i in stamp:
  16. dfs(num_sum+i,n+1)
  17. if stamp[len(stamp)-1]>1:
  18. print(0)
  19. else:
  20. flags=[[0,-1] for i in range(N*stamp[0]+1)]
  21. dfs(0,0)
  22. for i in range(len(flags)):
  23. if flags[i][0]==0:
  24. print(i-1)
  25. break

九.邮票面值设计(dfs回溯加动态规划)

给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤13)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1~MAX之间的每一个邮资值都能得到。
例如,N=3,K=2,如果面值分别为1分、4分,则在1分~6分之间的每一个邮资值都能得到(当然还有8分、9分和12分);如果面值分别为1分、  3分,则在1分~7分之间的每一个邮资值都能得到。可以验证当N=3,K=2时,7分就是可以得到的连续的邮资最大值,所以MAX=7,面值分别为1分、  3分。

思路:动态规划加dfs,dp[i]记录总牌数达到i所需的最小牌的数目,如果dp[i]数目大于N则最大的总牌数为i-1,如上题利用dfs记录寻找最大的牌数及其组合

  1. N,M=map(int,input().strip().split())
  2. arr=[]
  3. ans=[0 for i in range(M)]
  4. max_ans=-1
  5. def init_dp():
  6. global arr,N,M
  7. dp=[float('inf') for i in range(500)]
  8. dp[0]=0
  9. for j in range(len(dp)):
  10. for i in range(len(arr)):
  11. if j-arr[i]>=0:
  12. dp[j]=min(dp[j],dp[j-arr[i]]+1)
  13. if dp[j]>N:
  14. return j-1
  15. def dfs(max_num,count):
  16. global N,M,arr,ans,max_ans
  17. if count==M:
  18. if max_num>max_ans:
  19. for i in range(len(arr)):
  20. ans[i]=arr[i]
  21. max_ans=max_num
  22. return
  23. for i in range(max_num+1,arr[len(arr)-1],-1):
  24. arr.append(i)
  25. dfs(init_dp(),count+1)
  26. arr.pop()
  27. arr.append(1)
  28. dfs(N,1)
  29. for i in ans:
  30. print(i,end=' ')
  31. print()
  32. print("MAX={}".format(max_ans))

十.字符串编辑

从键盘输入一个字符串,并以字符’.’结束。编辑功能有:
1  D:删除一个字符,命令的方式为:D  a  其中a为被删除的字符,例如:D  s  表示删除字符’s’,若字符串中有多个  ‘s’,则删除第一次出现的。
2  I:插入一个字符,命令的格式为:I  a1  a2  其中a1表示插入到指定字符前面,a2表示将要插入的字符。例如:I  s  d  表示在指定字符  ’s’  的前面插入字符  ‘d’  ,若原串中有多个 ‘s’,则插入在最后一个字符的前面。
3  R:替换一个字符,命令格式为:R  a1  a2  其中a1为被替换的字符,a2为替换的字符,若在原串中有多个a1则应全部替换。
在编辑过程中,若出现被改的字符不存在时,则给出提示信息。

思路:很简单的一个模拟

  1. s=input().strip()
  2. order=list(input().strip().split())
  3. flag=True
  4. if order[0]=='D':
  5. for i in range(len(s)):
  6. if s[i]==order[1]:
  7. s=s[:i]+s[i+1:]
  8. print(s)
  9. flag=False
  10. break
  11. elif order[0]=='R':
  12. for i in range(len(s)):
  13. if s[i]==order[1]:
  14. flag=False
  15. s=s[:i]+order[2]+s[i+1:]
  16. if not flag:
  17. print(s)
  18. else:
  19. for i in range(len(s)-1,-1,-1):
  20. if s[i]==order[1]:
  21. flag=False
  22. s=s[:i]+order[2]+s[i:]
  23. print(s)
  24. break
  25. if flag:
  26. print("no exist")

十一.删除多余括号

从键盘输入一个含有括号的四则运算表达式,要求去掉可能含有的多余的括号,结果要保持原表达式中变量和运算符的相对位置不变,且与原表达式等价,不要求化简。另外不考虑'+''-'用作正负号的情况,即输入表达式不会出现(+a)或(-a)的情形。

思路:利用正则表达式将表达式的所有括号作为分隔符将单词分隔开,再记录每个单词中最小优先级的符号和单词开头和结尾的符号(这会影响旁边的括号),如果单词中最小的符号优先级大于旁边的优先级,则括号可以去除,(a*b)/c和(a+b)-c除外.

  1. import re
  2. d=dict()
  3. d['+']=1
  4. d['-']=2
  5. d['*']=3
  6. d['/']=4
  7. def words_work(words):
  8. ans=''
  9. level=[0 for i in range(len(words)+2)]
  10. per_level=[0 for i in range(len(words)+2)]
  11. for i in range(len(words)):
  12. fmin=5
  13. for j in words[i]:
  14. if j in ['+','-','*','/']:
  15. if d[j]<fmin:
  16. fmin=d[j]
  17. if words[i][0] in ['+','-','*','/']:
  18. per_level[i+1]=d[words[i][0]]
  19. if words[i][-1] in ['+','-','*','/']:
  20. per_level[i+1]=d[words[i][-1]]
  21. if fmin!=5:
  22. level[i+1]=fmin
  23. for i in range(len(words)):
  24. if (level[i+1]>=per_level[i] and level[i+1]>=per_level[i+2]) or len(words[i])==1 or(level[i+1]>=per_level[i] and level[i+1]==1 and per_level[i+2]==2) or(level[i+1]>=per_level[i] and level[i+1]==3 and per_level[i+2]==4):
  25. ans+=words[i]
  26. else:
  27. ans+='('+words[i]+')'
  28. print(ans)
  29. while True:
  30. try:
  31. in_put = re.split('[()]', input().strip())
  32. words = []
  33. for i in in_put:
  34. if i:
  35. words.append(i)
  36. words_work(words)
  37. except:
  38. break

十二.稍大的串

串可以按照字典序进行比较。例如:
  abcd 小于 abdc
  如果给定一个串,打乱组成它的字母,重新排列,可以得到许多不同的串,在这些不同的串中,有一个串刚好给定的串稍微大一些。科学地说:它是大于已知串的所有串中最小的串。你的任务就是求出这个“稍大的串”。

思路:利用python实现c++stl库中的next_permutation方法

  1. def next_permutation(a):
  2. """Generate the lexicographically next permutation inplace.
  3. https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
  4. Return false if there is no next permutation.
  5. """
  6. # Find the largest index i such that a[i] < a[i + 1]. If no such
  7. # index exists, the permutation is the last permutation
  8. for i in reversed(range(len(a) - 1)):
  9. if a[i] < a[i + 1]:
  10. break # found
  11. else: # no break: not found
  12. return False # no next permutation
  13. # Find the largest index j greater than i such that a[i] < a[j]
  14. j = next(j for j in reversed(range(i + 1, len(a))) if a[i] < a[j])
  15. # Swap the value of a[i] with that of a[j]
  16. a[i], a[j] = a[j], a[i]
  17. # Reverse sequence from a[i + 1] up to and including the final element a[n]
  18. a[i + 1:] = reversed(a[i + 1:])
  19. return True
  20. n=input()
  21. nn=[i for i in n]
  22. next_permutation(nn)
  23. print(''.join(nn))

十三.生物芯片

X博士正在研究一种生物芯片,其逻辑密集度、容量都远远高于普通的半导体芯片。
博士在芯片中设计了 n 个微型光源,每个光源操作一次就会改变其状态,即:点亮转为关闭,或关闭转为点亮。
这些光源的编号从 1 到 n,开始的时候所有光源都是关闭的。
博士计划在芯片上执行如下动作:
所有编号为2的倍数的光源操作一次,也就是把 2 4 6 8 ... 等序号光源打开
  所有编号为3的倍数的光源操作一次, 也就是对 3 6 9 ... 等序号光源操作,注意此时6号光源又关闭了。
所有编号为4的倍数的光源操作一次。
.....
直到编号为 n 的倍数的光源操作一次。

X博士想知道:经过这些操作后,某个区间中的哪些光源是点亮的。

思路:这是在计算因数的个数的奇偶,判断是否是平方数就可以

  1. N,L,R=map(int,input().strip().split())
  2. def yinshu(n):
  3. return (n**0.5-int(n**0.5))==0
  4. lights=[yinshu(i) for i in range(L,R+1)]
  5. print(lights.count(False))

十四.切开字符串

Pear有一个字符串,不过他希望把它切成两段。
这是一个长度为N(<=10^5)的字符串。
Pear希望选择一个位置,把字符串不重复不遗漏地切成两段,长度分别是t和N-t(这两段都必须非空)。
Pear用如下方式评估切割的方案:
定义“正回文子串”为:长度为奇数的回文子串。
设切成的两段字符串中,前一段中有A个不相同的正回文子串,后一段中有B个不相同的非正回文子串,则该方案的得分为A*B。
注意,后一段中的B表示的是:“...非正回文...”,而不是: “...正回文...”。
那么所有的切割方案中,A*B的最大值是多少呢?

思路:分别正序和倒序遍历字符串,找到以i为结尾的正回文子串或者非正回文子串,再求前缀和,查找最大项

  1. n=int(input())
  2. string=input().strip()
  3. is_same=set()
  4. not_same=set()
  5. def is_son(s):
  6. global is_same
  7. if len(s)%2==0:
  8. return False
  9. if s in is_same:
  10. return False
  11. return s==s[::-1]
  12. sum_son=[0 for i in range(n)]
  13. sum_not_son=[0 for i in range(n)]
  14. for i in range(len(string)-1):
  15. for j in range(i,len(string)):
  16. if is_son(string[i:j+1]):
  17. sum_son[j]+=1
  18. is_same.add(string[i:j+1])
  19. ss=string[::-1]
  20. for i in range(len(string)-1):
  21. for j in range(i,len(string)):
  22. if not is_son(ss[i:j+1]) and ss[i:j+1] not in is_same and ss[i:j+1] not in not_same:
  23. sum_not_son[j]+=1
  24. not_same.add(ss[i:j+1])
  25. for j in range(1,n):
  26. sum_son[j]+=sum_son[j-1]
  27. sum_not_son[j]+=sum_not_son[j-1]
  28. ans=0
  29. sum_not_son.reverse()
  30. for i in range(2,n-2):
  31. ans=max(ans,sum_son[i]*sum_not_son[i+1])
  32. print(ans)

十五.输出米字型

根据输入的正整数n 

米字形由一个(2n-1)*(2n-1)的矩阵组成,矩阵包含从大写A开始的n个字母

例如:n=3时,包含A,B,C;n=4时,包含A,B,C,D。
矩阵的正中间为n个字母中字典序最大的那个,从这个字母开始,沿着西北、正北、东北、正西、正东、西南、正南、东南八个方向各有一条由大写字母组成的直线。并且直线上的字母按字典序依次减小,直到大写字母A。
矩阵的其它位置用英文句号.填充。

思路:找规律题

  1. n=int(input().strip())
  2. for i in range(n-1):
  3. for j in range(i):
  4. print('.',end='')
  5. print(chr(ord('A')+i),end='')
  6. for j in range((2*n-4-2*i)//2):
  7. print('.',end='')
  8. print(chr(ord('A')+i),end='')
  9. for j in range((2*n-4-2*i)//2):
  10. print('.',end='')
  11. print(chr(ord('A')+i),end='')
  12. for j in range(i):
  13. print('.',end='')
  14. print()
  15. for i in range(n):
  16. print(chr(ord('A')+i),end='')
  17. for i in range(n-2,-1,-1):
  18. print(chr(ord('A')+i),end='')
  19. print()
  20. for i in range(n-2,-1,-1):
  21. for j in range(i):
  22. print('.',end='')
  23. print(chr(ord('A')+i),end='')
  24. for j in range((2*n-4-2*i)//2):
  25. print('.',end='')
  26. print(chr(ord('A')+i),end='')
  27. for j in range((2*n-4-2*i)//2):
  28. print('.',end='')
  29. print(chr(ord('A')+i),end='')
  30. for j in range(i):
  31. print('.',end='')
  32. print()

十六.比赛安排

设有有2^n(n<=6)个球队进行单循环比赛,计划在2^n–1天内完成,每个队每天进行一场比赛。设计一个比赛的安排,使在2^n–1天内每个队都与不同的对手比赛。

思路:深度优先搜索遍历,利用set记录已经遍历过的组合(只能保存元组),再用字典保存当天已经遍历过的人

  1. from collections import defaultdict
  2. n=int(input().strip())
  3. s=set()
  4. def dfs(day):
  5. global n,s
  6. d=defaultdict(int)
  7. if day==2**n:
  8. return
  9. print("<{}>".format(day),end='')
  10. for i in range(1,2**n):
  11. for j in range(i+1,2**n+1):
  12. if not (i,j) in s and d[i]==0 and d[j]==0 : ##集合里面只能跟元组
  13. d[i]=1
  14. d[j]=1
  15. s.add((i,j))
  16. print("{}-{}".format(i,j),end=' ')
  17. break
  18. print()
  19. dfs(day+1)
  20. dfs(1)

十七.分考场

n个人参加某项特殊考试。
为了公平,要求任何两个认识的人不能分在同一个考场。
求是少需要分几个考场才能满足条件。

思路:图的染色问题,利用dfs,对于每一个人可以分为加入已经存在的考场(如果不冲突)和新加一个考场的两类选择,如果遍历的房间数大于之前保存的答案则剪枝

  1. n=int(input().strip())
  2. m=int(input().strip())
  3. road=[[0 for i in range(n)] for j in range(n)]
  4. flag=[[-1 for j in range(n)] for i in range(n)]
  5. for i in range(m):
  6. ii,jj=map(int,input().strip().split())
  7. road[ii-1][jj-1]=1
  8. road[jj-1][ii-1]=1
  9. ans=n
  10. def dfs(num,room):
  11. global n,ans,flag
  12. if room>=ans:
  13. return
  14. if num==n:
  15. if room<ans:
  16. ans=room
  17. return
  18. for i in range(room):
  19. for j in range(n):
  20. if flag[i][j]==-1:
  21. flag[i][j]=num
  22. dfs(num+1,room)
  23. flag[i][j]=-1
  24. break
  25. if road[flag[i][j]][num]==1:
  26. break
  27. flag[room][0]=num
  28. dfs(num+1,room+1)
  29. flag[room][0]=-1
  30. dfs(0,1)
  31. print(ans)

十八.小数第n位

我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数。
如果我们把有限小数的末尾加上无限多个0,它们就有了统一的形式。
本题的任务是:在上面的约定下,求整数除法小数点后的第n位开始的3位数。

思路:分为三种情况:1.不存在循环 2.循环小数但是不从第一位开始循环 3.循环小数且从第一位循环

求出循环节对n取余数,输出答案

  1. from collections import defaultdict
  2. a,b,n=map(int,input().strip().split())
  3. a=a%b
  4. string=defaultdict(int)
  5. ans=''
  6. flag=True
  7. jie=[]
  8. while True:
  9. c=str(a*10//b)
  10. a=a*10%b
  11. if string[a]==1:
  12. if c==ans[0]:#循环从第一位开始
  13. jie=ans[ans.index(c):]
  14. ans=ans[:ans.index(c)]
  15. else:#循环不从第一位开始
  16. ans+=c
  17. jie=ans[ans.index(str(a*10//b)):]
  18. ans=ans[:ans.index(str(a*10//b))]
  19. break
  20. else:
  21. string[a]=1
  22. ans+=c
  23. if a==0:
  24. flag=False
  25. break
  26. n-=1
  27. if flag:
  28. if n>=len(ans):
  29. n=(n-len(ans))%len(jie)
  30. print("{}{}{}".format(jie[n],jie[(n+1)%len(jie)],jie[(n+2)%len(jie)]))
  31. else:
  32. n = n % len(ans)
  33. ans+=jie
  34. print("{}{}{}".format(ans[n],ans[(n+1)],ans[(n+2)]))
  35. else:
  36. for ii in range(3):
  37. if n+ii<len(ans):
  38. print(ans[n+ii],end='')
  39. else:
  40. print(0,end='')

十九.奇怪的数列

从X星截获一份电码,是一些数字,如下:
13
1113
3113
132113
1113122113
....
YY博士经彻夜研究,发现了规律:
第一行的数字随便是什么,以后每一行都是对上一行“读出来”
比如第2行,是对第1行的描述,意思是:1个1,1个3,所以是:1113
第3行,意思是:3个1,1个3,所以是:3113
请你编写一个程序,可以从初始数字开始,连续进行这样的变换。

  1. s=input().strip()
  2. n=int(input().strip())
  3. def change(s):
  4. ans=''
  5. num=s[0]
  6. temp_num=0
  7. for i in s:
  8. if i==num:
  9. temp_num+=1
  10. else:
  11. ans+=str(temp_num)
  12. ans+=num
  13. num=i
  14. temp_num=1
  15. ans+=str(temp_num)
  16. ans+=num
  17. return ans
  18. for j in range(n):
  19. s=change(s)
  20. print(s)

二十.路径之谜

小明冒充X星球的骑士,进入了一个奇怪的城堡。城堡里边什么都没有,只有方形石头铺成的地面。
假设城堡地面是 n x n 个方格。【如图1.png】所示。
按习俗,骑士要从西北角走到东南角。
可以横向或纵向移动,但不能斜着走,也不能跳跃。
每走到一个新方格,就要向正北方和正西方各射一箭。
(城堡的西墙和北墙内各有 n 个靶子)

同一个方格只允许经过一次。但不必走完所有的方格。
如果只给出靶子上箭的数目,你能推断出骑士的行走路线吗?
有时是可以的,比如图1.png中的例子。
本题的要求就是已知箭靶数字,求骑士的行走路径(测试数据保证路径唯一)

思路:dfs剪枝回溯

  1. N=int(input().strip())
  2. up=list(map(int,input().strip().split()))
  3. left=list(map(int,input().strip().split()))
  4. ans=[]
  5. def dfs(i,j):
  6. global N,up,left,ans
  7. if up[j]==0 or left[i]==0:
  8. return
  9. else:
  10. up[j]-=1
  11. left[i]-=1
  12. if sum(up) == 0 and sum(left) == 0:
  13. if i==N-1 and j==N-1:
  14. for ii in ans:
  15. print(ii, end=' ')
  16. return
  17. if i > 0:
  18. if (i - 1) * N + j not in ans:
  19. ans.append((i - 1) * N + j)
  20. dfs(i - 1, j)
  21. ans.pop()
  22. if j > 0:
  23. if i * N + j - 1 not in ans:
  24. ans.append(i * N + j - 1)
  25. dfs(i, j - 1)
  26. ans.pop()
  27. if i < N - 1:
  28. if (i + 1) * N + j not in ans:
  29. ans.append((i + 1) * N + j)
  30. dfs(i + 1, j)
  31. ans.pop()
  32. if j < N - 1:
  33. if i * N + j + 1 not in ans:
  34. ans.append(i * N + j + 1)
  35. dfs(i, j + 1)
  36. ans.pop()
  37. up[j]+=1
  38. left[i]+=1
  39. ans.append(0)
  40. dfs(0,0)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/929629
推荐阅读
相关标签
  

闽ICP备14008679号