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 }

 

posted @ 2016-09-18 11:48  刺猬的玻璃心碎了  阅读(1826)  评论(4编辑  收藏  举报