Solution
4.2:
第一關:
求個導發現有兩個根,分別二分就行了
import numpy as np E = 1e-6 ########## begin ########## # 請在此填寫代碼, 計算6*np.exp(x)-113*x+17=0的根 def f(x): return 6*np.exp(x)-113*x+17 def divd(L,R): while(L<R): mid=(L+R)/2 if(abs(f(mid))<=E): return mid if(f(mid)<-E): R=mid else: L=mid def div(L,R): while(L<R): mid=(L+R)/2 if(abs(f(mid))<=E): return mid if(f(mid)>-E): R=mid else: L=mid print("%.4f"%divd(0,1.0)) print("%.4f"%div(4.0,5.0)) ########## end ##########
第二關:
不難發現h的值依賴於角度θ,且θ滿足sinθ/θ=L/S,即S×sinθ/θ-L=0 對該式求導,發現其單減,且顯然0<θ<π/2,故二分求θ即可
又因為有h=L/2*tan(θ/2),這樣就做完了
from math import * L, n, C = map(float, input().split()) E=1e-8 S=(1+n*C)*L def divd(l,r): while(l<r): mid=(l+r)/2 val=S*sin(mid)/mid-L if(abs(val)<=E): return mid if(val<-E): r=mid else: l=mid t=divd(0,pi/2) h=L/2*tan(t/2) ########## begin ########## # 請在此填寫代碼,求方程的根 ########## end ########## print('%.4f' % h)
4.3:
第一關:
顯然由某一個點出發的最小積依賴於由他下方點出發的最小積或右下方出發的最小積,取二者中的最小值
n = eval(input()) dp=[] for i in range(n): X = dp.append(list(map(int, input().split()))) for i in range(n-2,0,-1): for j in range(0,i+1,1): dp[i][j]*=min(dp[i+1][j+1],dp[i+1][j]) dp[0][0]*=min(dp[1][0],dp[1][1]) print(dp[0][0]
第二關:
遞歸太麻煩了,for循壞可以O(n)搞完,效率更高還好寫
dp[i]表示以i為起點的最大子序列積,有dp[i]=max(dp[i+1]×A[i],dp[i])(分別對應將A[i]加入以A[i+1]為起始的最大子序列或不加入單獨考慮)
最末尾顯然只能單獨考慮,有dp[n-1]=A[n-1],倒序for一遍,再取最大的dp[i]即可
代碼中把A列表和dp列表共用了,不影響正確性
n = eval(input()) A= list(map(float, input().split())) for i in range(n-2,0,-1): A[i]=max(A[i],A[i+1]*A[i]) A[0]=max(A[0],A[1]*A[0]) ans=0.0 for i in range(0,n,1): ans=max(ans,A[i]) print("%.2f"%(ans)
4.4:
第一題的話,考慮歸並,先二分再合並,合並時注意兩個子點集之間的配對情況
第二題,實際上和第一題一樣,只不過處理的時候注意一下兩個點的分組情況,只有不同組的時候才需要處理
第一關:

from math import * n = eval(input()) A=[] for i in range(n): x,y= map(int, input().split()) A.append((x,y)) def Distance(a, b): return sqrt((a[0]-b[0])**2+(a[1]-b[1])**2) #求[low..high]區間內的最小點距 def FidMin(A,L,R): ########## begin ########## # 請在此填寫代碼,返回區間[low,high]的最小點距 mid=(L+R)//2 if(L==R): return 1e9 if(L==R-1): return Distance(A[L],A[R]) d=min(FidMin(A,L,mid),FidMin(A,mid+1,R)) tmp=[] p0=A[mid] for i in range(L,R+1,1): p1=A[i] if(abs(p1[0]-p0[0])=d): break d=min(d,Distance(tmp[i],tmp[j])) return d ########## end ########## A.sort() result=FidMin(A,0,len(A)-1) print('%.3f' % result)
第二關:

import math n = eval(input()) A=[] for i in range(n*2): group = 1 if i<n else 2 x,y= map(int, input().split()) A.append((x,y,group)) def Distance(a, b): return math.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2) #求[low..high]區間內的最小點距 def FidMin(A,L,R): ########## begin ########## # 請在此填寫代碼,返回區間[low,high]的最小點距,且這兩點屬於不同的組 mid=(L+R)//2 if(L==R): return 1e9 if((L==R-1) and (A[L][2]==A[R][2])): return 1e9 if(L==R-1): return Distance(A[L],A[R]) d=min(FidMin(A,L,mid),FidMin(A,mid+1,R)) tmp=[] p0=A[mid] for i in range(L,R+1,1): p1=A[i] if(abs(p1[0]-p0[0])<d): tmp.append(p1) tmp.sort(key=lambda x:x[1]) upp=len(tmp)-1 for i in range(0,upp+1,1): for j in range(i+1,upp+1,1): if(abs(tmp[i][1]-tmp[j][1])>=d): break if(tmp[i][2]!=tmp[j][2]): d=min(d,Distance(tmp[i],tmp[j])) return d ########## end ########## A.sort() result=FidMin(A,0,len(A)-1) print('%.3f' % result)
4.5:
第一關:
遞歸就行了,先序遍歷,每訪問一個點答案+1

def CalcNodes(tree): ########## begin ########## # 請在此填寫代碼 if(len(tree)==0): return 0 return 1+CalcNodes(tree[1])+CalcNodes(tree[2]) ########## end ##########
第二關:
中序中,根節點所在位置左邊的序列就是左子樹的中序序列,右邊就是右子樹的中序序列
然后先序序列其實就是根+左子樹的先序序列+右子樹的先序序列
后序序列是左子樹后序+右子樹后序+根

#pre_order:先根序列 in_order:中根序列 #要求返回后跟序列 def get_postorder(pre_order, in_order): ########## begin ########## # 請在此填寫代碼 l=len(in_order) if(l==0): return '' root=pre_order[0] if(l==1): return root for i in range(0,l,1): if(in_order[i]==root): pos=i break pol='' por='' iol='' ior='' for i in range(1,1+pos,1): pol=pol+pre_order[i] for i in range(1+pos,l,1): por=por+pre_order[i] for i in range(0,pos,1): iol=iol+in_order[i] for i in range(pos+1,l,1): ior=ior+in_order[i] p1=get_postorder(por,ior) p2=get_postorder(pol,iol) return p2+p1+root ########## end ##########
4.6:
第一關:
由於本題我們只關心序列的合法性,對於左括號,入棧,對於右括號,不必入棧,只需要與棧頂的左括號相匹配,匹配成功就繼續處理下一個括號,失敗就直接輸出false
全部括號都處理完成后,如果棧內仍有未匹配的左括號,還是輸出false
在處理過程中,記得留意空棧的情況

from queue import LifoQueue #括號匹配 S=input() #輸入的字符串 sta=[] ########## begin ########## # 請在此填寫代碼 tot=0 ans=True def match(x,y): if(x=='[' and y==']'): return True if(x=='(' and y==')'): return True if(x=='{' and y=='}'): return True return False for i in S: if(i=='[' or i=='(' or i=='{'): sta.append(i) tot+=1 else: if(tot==0): ans=False break if(match(sta[tot-1],i)): del sta[tot-1] tot-=1 else: ans=False break if(tot!=0): ans=False print(ans)
第二關:
與上一關有些不同,棧里維護的是括號在原字符串的索引而不是括號本身
新增一個ok列表,ok[i]表示第i位的括號是否匹配成功,ok[i]=1表示成功,ok[i]=0則是失敗
匹配方法則與第一關類似,但因為需要計數,所以這里右括號也要入棧
最開始ok[i]均設為0,匹配成功,把這組左右括號對應的ok[i]改為1
答案就是ok[i]列表中最長的連續為1的子段的長度
復雜度O(n)

from queue import LifoQueue #括號匹配 S=input() #輸入的字符串 sta=[] ok=[] ########## begin ########## # 請在此填寫代碼 tot=0 ans=0 cnt=0 def match(x,y): if(x=='[' and y==']'): return True if(x=='(' and y==')'): return True if(x=='{' and y=='}'): return True return False l=len(S) for i in range(0,l,1): ok.append(0); for i in range(0,l,1): if(S[i]=='[' or S[i]=='(' or S[i]=='{'): sta.append(i) tot+=1 else: if(tot==0): sta.append(i) tot+=1 elif(match(S[sta[tot-1]],S[i])): ok[i]=1 ok[sta[tot-1]]=1 del sta[tot-1] tot-=1 else: sta.append(i) tot+=1 for i in range(0,l,1): if(ok[i]==1): cnt+=1 ans=max(ans,cnt) else: cnt=0 print(ans)