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 ",0.0); 75 } 76 else { 77 DFS(2,2,n);//从节点2开始枚举。刚好就只有2个位置。 78 if(ans==-1)printf("-1 "); 79 else printf("%.10lf ",ans); 80 } 81 } 82 return 0; 83 }