uva1354 天平難題。主要有 回溯法,二叉樹模擬。
當然,這道題也有很多剪枝,但是這個用二叉樹性質模擬的數組應該過了,這樣寫,這道題,完全就足夠了。
原題目鏈接:https://uva.onlinejudge.org/external/13/1354.pdf
題目大意:
就是首先給你一個房間的寬度r,之后有s個掛墜,第i個掛墜的重量是wi,設計一個盡量寬,但是不能寬過房間.的天平。當然會有好幾組這樣的數據。
這些天平棍的長度都為1,天平棍要么掛 掛墜,要么就繼續掛木棍設掛的木棍必須要讓天平平衡,滿足n*a==m*b。這就是個物理概念。
其它東西,題目里寫的很清楚。
而這道題整體思想就是 1,枚舉二叉樹。2,計算寬度。
枚舉二叉樹,很顯然用到的是dfs+回溯。
二叉樹的模型,主要就用的是這個東西來枚舉 like根==i子節點== i*2,i*2+1,這樣的。
從第二個點開始枚舉。其中dfs(num,sit,use)
num:代表這個節點編號,
sit:現在這棵樹中有多少位置可供填寫。
use:現在有use個掛件還可以用。
PS:枚舉的時候還要注意,每次進到一個新點的時候要判斷父親節點是不是天平棍,-1為棍,如果不是棍,就++,找下一個節點。
計算寬度的時候,從最后一個點開始往前遞推。設以這個節點為0,左邊就是負長度,而右邊就是正長度。這就很好的解釋了其中
l[i]=min(-L+l[x],R+l[y]);
r[i]=max(-L+r[x],R+r[y]);
這段代碼的意思。
1 #include<cstdio> 2 #include<algorithm> 3 #include<string.h> 4 using namespace std; 5 double val[10],l[105],r[105],w[10],ans,room; 6 int n,t[105],visit[105]; 7 int judge(int x) 8 { 9 memset(l,0,sizeof(l)); 10 memset(r,0,sizeof(r)); 11 memset(val,0,sizeof(val)); 12 for(int i=x;i;i--) 13 { 14 if(t[i]==-1){ //是天平棍,對它的子節點進行處理。 15 int x=i*2,y=i*2+1; 16 val[i]=val[y]+val[x]; 17 double L=val[y]/val[i]; 18 double R=val[x]/val[i]; 19 l[i]=min(-L+l[x],R+l[y]); 20 r[i]=max(-L+r[x],R+r[y]); 21 } 22 else if (t[i])//或者是掛件。只計量掛件的重量就行了。 23 { 24 val[i]=w[t[i]]; 25 } 26 } 27 double a=r[1]-l[1]; 28 if(a-room<1e-5)ans=max(ans,a); 29 } 30 int DFS(int num,int sit,int use) 31 { 32 if(use==0){//所有的掛件都放完了,開始計算長度。 33 judge(num-1); 34 return 0; 35 } 36 if(t[num/2]!=-1){//父親節點不是棍子,就不能往下放東西。 37 DFS(num+1,sit,use); 38 } 39 else 40 { 41 if(use>sit){//掛件要比位置多,創位置。 42 t[num]=-1; 43 DFS(num+1,sit+1,use); 44 t[num]=0; 45 } 46 if(sit==1&&use>1) return 0; 47 for(int i=1;i<=n;i++) 48 { 49 if(!visit[i]){ 50 visit[i]=1; 51 t[num]=i; 52 DFS(num+1,sit-1,use-1);//放掛件 53 visit[i]=0; 54 t[num]=0; 55 } 56 } 57 } 58 } 59 int main() 60 { 61 int tot; 62 scanf("%d",&tot); 63 while(tot--) 64 { 65 scanf("%lf%d",&room,&n); 66 memset(w,0,sizeof(w)); 67 memset(t,0,sizeof(t)); 68 memset(visit,0,sizeof(visit)); 69 for(int i=1;i<=n;i++) 70 scanf("%lf",&w[i]); 71 ans=-1; 72 t[1]=-1; //第一個根就是個棍。 73 if(n==1){ 74 printf("%.10lf\n",0.0); 75 } 76 else { 77 DFS(2,2,n);//從節點2開始枚舉。剛好就只有2個位置。 78 if(ans==-1)printf("-1\n"); 79 else printf("%.10lf\n",ans); 80 } 81 } 82 return 0; 83 }