计算组合数
def cnm(n,m):
if(m < n-m): m = n-m
a = 1;b = 1;ans = 0
for i in range(m+1,n+1):
a *= i
b *= (i-m)
print(a//b)
cnm(21,1)
这道题本身很简单,但是一个注意一点,利用m<n-m
进行优化是有意思的小技巧.
猜测字谜游戏:输入单词和猜测,并输出结果。题目非常的直白,没有什么难度,唯一需要注意的是,我采用了set这个类型强行将guess里面重复的猜测去掉,并且用重复值的个数初始化错误出现的次数.
def hangman(ans,guess):
is_win_lost_chk = 0
length = len(guess)
guess = ''.join(set(guess))
mistake_occur = length - len(guess)
right_occur = 0
msg = ['You win','You chickened out','You lose']
for each in guess:
tmp_is_occur = False
for ch in ans:
if each==ch:right_occur+=1;tmp_is_occur = True
if(not tmp_is_occur):mistake_occur+=1
if(mistake_occur==7):break
if(mistake_occur==7):is_win_lost_chk = 2
elif(right_occur==len(ans)):is_win_lost_chk = 0
else:is_win_lost_chk = 1
print(msg[is_win_lost_chk])
hangman('cheese','abcdefgij')
1UVA133:这题有点烦…因为第一次指的时候,那个人是算一次的,但是指完一次以后,那个人由于被移走了,所以官员应该指向下一个人.
def dole_queue(n,k,m):
queue = [i+1 for i in range(0,n)]
index_a = 0;index_b = n-1;
left = n
def go(index,d,t):
nonlocal n
while(True):
if(queue[index]!=0):t-=1
if(t==0):break;
index = (index+d)%n
return index
while(left>0):
index_a = go(index_a,1,k)
index_b = go(index_b,-1,m)
if(index_a!=index_b):
left-=2
print(index_a+1,index_b+1)
else:
left-=1
print(index_a+1)
queue[index_a],queue[index_b] = 0,0
dole_queue(10,4,3)
下面采用队列进行人走之后移动元素,换一种解题思路:
def myqueue(n,k,m):
queue = deque([i+1 for i in range(0,n)])
a = 1;b = n;
def go():
def getnext():
_p1,_p2 = (p1+1)%n,(p2-1)%n
while(_p1 == p2):_p1 = (_p1+1)%n
while(_p2 == p1):_p2 = (_p2-1)%n
return queue[_p1],queue[_p2]
nonlocal n,a,b
p1 = queue.index(a)
p1 = (p1+k-1)%n
p2 = queue.index(b)
p2 = (p2-(m-1))%n
t1,t2 = queue[p1],queue[p2]
a,b = getnext()
if(p1==p2):print(t1);queue.remove(t1)
else:print(t1,t2);queue.remove(t1);queue.remove(t2)
n = n - (1 if(p1==p2)else 2)
while(n>1):
go()
print(queue[0])
下面是书本上的解法,有些地方非常巧妙:
def dole_queue(n,k,m):
queue = [i for i in range(0,n+1)]
p1 = n;p2 = 1;
left = n
def go(index,d,t):
nonlocal n
while(t>0):
while(True):
index = (index+d+n-1)%n+1
if(queue[index]!=0):break
t-=1
return index
while(left>0):
p1 = go(p1,1,k)
p2 = go(p2,-1,m)
if(p1!=p2):
left-=2
print(p1,p2)
else:
left-=1
print(p1)
queue[p1],queue[p2] = 0,0
dole_queue(10,4,3)
首先. index = (index+d+n-1)%n + 1这句话就让人有些困惑,仔细研究了一下,对于d = 1,其实就是index = (index+1)%n + 1(范围变成1,n),但是这样写对于d = -1的情况是不一样的,注意,如果写成index = (index-1)%n+1,当index = 1,结果变成了0,这不符合我们的预期,它应该是n才对,用书上的方法它就可以从1变成n.
当然,我们直接用0-n-1进行映射,最后输出加1的方式好像也不错,但是这个式子还是很巧妙,值得思考一下.它避免了对index==0的情况作特殊处理.
其次,它的初始值是n,1,这里不得不说方法很巧妙,我们的直觉都是写成1,n。包括我的第一种方法,但是这样做会陷入一种情况,那就是第一次数数和后面数数的情况有点不一样,第一次指向的人是没有数过的,但是后面每一次开始数的时候,第一个指向的人总是已经被移走的了!!!所以我必须将index 的变化放在循环内部的最后面,保证检测过后再变化…稍微有点不自然.
Uva213:信息解码问题,用字典来存储相应的编码情况.然后在解码的时候直接查询.
def mydecode(code,message):
def getnext(coding):
if(coding==''):return '0'
length = len(coding)
x = int(coding,2)
if(x == (2**(length) -2)):return '0'*(length+1)
else: return bin(x+1)[2:]
decoding = {}
coding = ''
for ch in code:
coding = getnext(coding)
decoding[coding] = ch
pos = 0;n = len(message)
while(pos<n):
length = int(message[pos:pos+3],2)
if(length == 0):break
pos += 3
while(True):
tmp = message[pos:pos+length]
if(tmp==('1'*length)):break
print(decoding[tmp],end = '')
pos += length
pos += length
mydecode('$#**\\','0100000101101100011100101')
追踪电子表格:UVa512。这个题目有两种思路,当然最好的办法不是模拟操作,而是计算要查询的表格的位置.我根据书上的第二种办法写的代码:仔细思考一下.算法复杂度大约是O(QC),qc分别是命令的条数和查询的次数.如果查询次数不太多的话这种办法的效率是更高的.需要注意插入和删除的区别。删除的比较条件是大于和等于分开处理,而插入则是大于等于一起处理.
def tracing_sheet(command,R,C,q):
def query(r,c):
pos = [[[i,j] for j in range(C+1)] for i in range(R+1)]
def swap(r1,c1,r2,c2):
pos[r1][c1],pos[r2][c2] = pos[r2][c2],pos[r1][c1]
def del_or_insert(curr_cmd,i_list):
if(curr_cmd == 'IR' ):x_y = 0;d = 1;
if(curr_cmd == 'IC' ):x_y = 1;d = 1;
if(curr_cmd == 'DR' ):x_y = 0;d = -1;
if(curr_cmd == 'DC' ):x_y = 1;d = -1
tot_diff = 0
x = pos[r][c][x_y] + (d+1)//2
for i in i_list:
if(x>i):pos[r][c][x_y] +=d
elif(curr_cmd[0] == 'D' and x==i):return False
return True
for tmp_cmd in command:
if(tmp_cmd[0] == '('):
val = [int(i) for i in tmp_cmd if i.isdigit()]
swap(val[0],val[1],val[2],val[3])
else:
cmd = tmp_cmd[1:3]
val = [int(i) for i in tmp_cmd if i.isdigit()][1:]
if(not del_or_insert(cmd,val)):print('Deleted ');return False
print('(%d,%d) => (%d,%d)'%(r,c,pos[r][c][0],pos[r][c][1]))
return True
for each_query in q:
query(each_query[0],each_query[1])
最后一个例题:这个题目真的比较麻烦,有点像作业题….但是没什么思维上的难度.唯一需要注意的是最后一个需求,输出各种信息,这里有一个问题:到底是按照功课来进行循环还是学生来循环,从输出看似乎应该是选择功课,但是观察到最后的需求,要输出所有的人通过的情况,这样按照功课来循环就很不好办了——好像必须这样做:把每一门功课内的学生情况记录下来然后最后汇总比较,这样就多了一个O(n)的空间需求。
因此按照学生来进行循环就比较符合最后需求的比较了,至于前面的输出问题可以把相关数据存储起来,最后再输出.
另外关于排名的问题,这里我就没有采取对数据排序的方式了,而是直接遍历一遍获得排名,这里涉及到一个权衡的问题,如果我们保持数据存储是线性的,那么每次插入就是O(N),但是输出排名的时候就只需要O(N)的复杂度.如果不保持线性,那么每次查询的时候就考虑是对整个表排序(桶排序是O(N)的时间|空间复杂度,快排式O(NlogN),这里可以考虑桶排),这样每M次查询就是O(MN+N)或者O(MN+NlogN),也可以考虑不排序,这样每一次查询都遍历一遍表,复杂度是O(MN*N),具体怎么选择还要看操作的频率了,另外]还可以考虑把表的结构作成复合结构,每一个班级是一个节点,班级内部有序而班级间无序,这样也可以提高效率…总之值得思考的地方很多.不要局限于做出来题目.
import pdb
class Student:
def __init__(self,args):
self.sid,self.cid,self.name,self.chinese,self.math,self.english,self.programming = args
self.tot_scores = int(self.chinese)+int(self.math)+int(self.english)+int(self.programming)
def Sheet():
record = []
SID = [0]*101
def print_menu():
print('Weclcome to student Performence\n')
print('1 - Add')
print('2 - Remove')
print('3 - Query')
print('4 - Show ranking')
print('5 - Show statistic')
print('0 - Exit')
def print_std(std):
def rank():
ranks = 1
for each in record:
if(std.tot_scores < each.tot_scores ):ranks += 1
return ranks
average_scores = std.tot_scores/4
print('*'*15)
print(rank(),std.sid,std.cid,std.name,std.chinese,std.math,std.english,std.programming,
std.tot_scores,'%.2f'%average_scores)
def add():
while(True):
print('Please enter the SID,CID,name,and four scores. Enter o to finsih')
curr_input = input()
if(curr_input == '0'):break
val = curr_input.split(' ')
print('*'*10,val)
if(SID[int(val[0])] != 0):print('Duplicate SID');
else:record.append(Student(val));SID[int(val[0])] = 1;
print(dir(Student(val)))
def DQ(isq_d):
while(True):
print('Please enter the SID,or name. Enter o to finsih')
curr_input = input()
if(curr_input == '0'):break
val = curr_input.split(' ')[0]
count = 0
for each_std in record:
if(each_std.sid == val or each_std.name == val):
if(isq_d == 'd'):count += 1;SID[int(each_std.sid)] = 0;each_std = 0;
elif(isq_d == 'q') :print_std(each_std)
if(isq_d == 'd'):
print('%d student(s) removed'%count)
def stat():
if(record == []):return
print('please enter the class ID,0,for the whole statistics')
try:
ID = int(input())
except:
return
conditions = ['chinese','math','english','programming']
information = {'chinese':[0,0],'math':[0,0],'english':[0,0],'programming':[0,0],'overall':[0,0,0,0,0]}
count = 0
for std in record:
passed_course = 0
if(ID == 0 or ID == int(std.cid)):
for each in conditions:
tmp_grade = int(getattr(std,each,None))
is_passed = 1 if(tmp_grade>=60) else 0
passed_course += is_passed
information[each][0] += tmp_grade
information[each][1] += is_passed
information['overall'][passed_course] += 1
count += 1
for each in conditions:
print(each)
print('Average Score: %.2f'% (information[each][0]/count))
print('Number of passed students: %d'%information[each][1])
print('Number of failed students: %d'%(count-information[each][1]))
print('Overall\nNumber of students who passed all subjects: %d'%(information['overall'][4]))
for i in range(3,0,-1):
print('Number of students who passed %d or more subjects: %d'%(i,information['overall'][i]))
print('Number of students who failed all subjects: %d'%(information['overall'][0]))
while(True):
print_menu()
choice = input()
if(choice=='0'):break
elif(choice=='1'):add()
elif(choice=='2'):DQ('d')
elif(choice=='3'):DQ('q')
elif(choice=='4'):print('Don\'t do that')
elif(choice=='5'):stat()
Sheet()
上面的代码简单测试了一下没有问题,可能有隐藏的bug,但是具体的框架没问题