uva1354 天平難題 解題報告


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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM