大致意思就是在一个房间里有一个正常操作的天平(符合杠杆定理),天平下面可以挂若干个子天平,求在房间放得下的情况下天平的最长长度。
过程基本就是标准的枚举,利用dfs就行。但是数组有点多,先对数组做个介绍。
w[i] i物体的重量,t[i] 位置i的物体的序号(如果是天平节点为-1),v[i] 就是vis数组,为啥不写vis呢 因为我是看别人代码写的没反应过来(小声) l[i] 从位置i到树底的最左边坐标 r[i]从位置i到树底的最右边坐标 val[i] 位置i的重量
dfs时要注意条件,如果物体只剩一个,是不能放子天平的(无法平衡);反过来,如果位置只有一个而重物超过一个,就没位置放下一个了。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,v[10],t[110];
double w[10],R,ans,l[110],r[110],val[110];
void init()
{
memset(v,0,sizeof(v));
memset(t,0,sizeof(t));
ans=-1;
t[1]=-1;
cin>>R>>n;
for(int i=1;i<=n;i++) cin>>w[i];
}
void judge(int u)
{
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
memset(val,0,sizeof(val));
for(int i=u;i>0;i--)
{
if(t[i]==-1)
{
int x=i*2,y=i*2+1;
val[i]=val[x]+val[y];
double Lt=val[y]/val[i];
double Rt=val[x]/val[i];
l[i]=min(l[x]-Lt,Rt+l[y]);
r[i]=max(r[x]-Lt,Rt+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 use)
{
if(use==0)
{
judge(u-1);
return;
}
if(t[u/2]!=-1)
dfs(u+1,m,use);
else
{
if(use>m)
{
t[u]=-1;
dfs(u+1,m+1,use);
t[u]=0;
}
if(m==1&&use>1)return;
for(int i=1;i<=n;i++)
if(!v[i])
{
v[i]=1;t[u]=i;
dfs(u+1,m-1,use-1);
v[i]=0;t[u]=0;
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
init();
if(n==1) printf("%.16lf\n",0.0);
else
{
dfs(2,2,n);
if(ans==-1) cout<<-1<<endl;
else printf("%.16lf\n",ans);
}
}
return 0;
}