UVa 1354 天平难题

题目链接

题目大意:给出房间的宽度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;
}

猜你喜欢

转载自blog.csdn.net/qq_40861069/article/details/81239550