题目大意:给出房间的宽度r和s个挂坠的重量,设计一个尽量宽(但不超过房间的宽度r)的天平。
解决问题点:由于节点的数目少,可以将整个天平(当作二叉树)枚举出来,然后计算宽度(实际上在构造二叉树的时候就可以计算),要注意左子树的宽度可能会大于根节点的做宽度,通过比较计算。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
struct Tree
{
double L,R;
Tree(int l=0,int r=0):L(l),R(r) {}
};
Tree tree[1<<6];
int node[1<<6],vis[1<<6];
int s,tid;
double r,maxl;
void dfs(int dep)
{
if(dep==s) //dfs的终点,此时计算整个的左右宽度,并比较
{
if(tree[tid].L+tree[tid].R<=r)
maxl=max(maxl,tree[tid].L+tree[tid].R);
}
else
for(int i=1; i<=tid; i++)
{
if(!vis[i])
{
for(int j=1; j<=tid; j++)
{
if(i!=j&&!vis[j]) //节点不同,没有被使用
{
vis[i]=vis[j]=1;
node[++tid]=node[i]+node[j]; //新生成的节点加在数组的后面
int wl=node[i],wr=node[j];
double a=(double)wr/(wl+wr);
double b=1.0-a;
tree[tid].R=max(b+tree[j].R,tree[i].R-a); //判断左右的宽度,注意问题
tree[tid].L=max(a+tree[i].L,tree[j].L-b);
dfs(dep+1);
vis[i]=vis[j]=vis[tid]=0;
tree[tid].R=tree[tid].L=0;
--tid;
}
}
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(tree,0,sizeof(tree));
tid=0;// tid树的结点的编号
cin>>r>>s;
for(int i=1; i<=s; i++)
{
cin>>node[i];
tid++;
}
maxl=-1;
memset(vis,0,sizeof(vis)); //标记数组置0
dfs(1);
if(maxl==-1)
{
printf("-1\n");
}
else
{
printf("%.16f\n",maxl);
}
}
return 0;
}