UVA 1354 Mobile Computing
题意:
给出房间的宽度r和s个挂坠的重量wi。设计一个尽量宽的天平(不能超过房间的宽度),挂着所有的挂坠。天平由长度为l的木棍组成,天平的一端不是挂坠就是另一个天平。必须满足n*a=m*b(l=a+b)。
分析:
建立一个二叉树,当前节点为-1代表放天平。dfs(u,m,la)u代表第几个节点,m代表目前有几个节点可用,la代表剩余几个挂坠。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 10;
const int M = 105;
const double INF = 0x3f3f3f3f;
int n,v[N],t[M];
double w[M],l[M],r[M],val[M],ans,R;
void judge(int u)//判断这种天平的宽度是不是合理
{
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
memset(val,0,sizeof(val));
int i;
for(i=u;i;i--)
{
if(t[i]==-1)//如果这个节点是天平的话记录他的左右长度。
{
int x=2*i,y=2*i+1;
val[i]=val[x]+val[y];
double Li=val[y]/val[i];
double Ri=val[x]/val[i];
l[i]=min(-Li+l[x],Ri+l[y]);
r[i]=max(-Li+r[x],Ri+r[y]);
}
else if(t[i])
{
val[i]=w[t[i]];
}
}
double tmp=r[1]-l[1];
if (tmp-R<1e-5&&tmp>ans)
ans=tmp;
}
void dfs(int u,int m,int la)
{
if(la==0)
{
judge(u-1);
return ;
}
if(t[u/2]!=-1)
{
dfs(u+1,m,la);
}
else
{
if(la>m)//如果剩余的挂坠数>可用的点,就把这个节点放天平,这样可用的节点数+1.
{
t[u]=-1;
dfs(u+1,m+1,la);
t[u]=0;
}
if(m==1&&la>1)
return;
for(int i=1;i<=n;i++)
{
if(!v[i])
{
v[i]=1;
t[u]=i;
dfs(u+1,m-1,la-1);
v[i]=0;
t[u]=0;
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(t,0,sizeof(t));
memset(v,0,sizeof(v));
scanf("%lf%d",&R,&n);
int i,j,k;
for(i=1;i<=n;i++)
scanf("%lf",&w[i]);
t[1]=-1;ans=-1;
if(n==1)
printf("%.10lf\n",0.0);
else
{
dfs(2,2,n);
if(ans==-1)
printf("-1\n");
else
printf("%.10lf\n",ans);
}
}
return 0;
}