搜索 【uva1354】 Mobile Computing (练习题7-7 天平难题)

7-7天平难题(Mobile Computing,uva 1354)
(mobile.cpp,Time Limit:3000MS )

题目描述:
给出房间的宽度r和s个挂坠的重量wi,设计一个尽量宽(但宽度不能超过房间宽度r)的天平,挂着所有挂坠。
天平由一些长度为1的木棍组成。木棍的每一端要么挂一个挂坠,要么挂另外一个木棍。如图1所示,设n和m分别是两端的总重量,要让天平平衡,必须满足n*a=m*b。

搜索 【uva1354】 Mobile Computing (练习题7-7 天平难题)_第1张图片

例如:如果有3个重量分别为1,1,2的挂坠,有3种平衡的天平,如下图所示:

搜索 【uva1354】 Mobile Computing (练习题7-7 天平难题)_第2张图片

挂坠的宽度忽略不计,且不同的子天平可以相互重叠。如下图所示,宽度为(1/3)+1+(1/4)。
搜索 【uva1354】 Mobile Computing (练习题7-7 天平难题)_第3张图片

输入格式:
输入第一行为数据组数。每组数据前两行为房间宽度r和挂坠数目s (0 < r < 10,1<=s<=6)。以下s行为一个挂坠的重量wi(1<=wi<=1000)。输入保证不存在天平的宽度恰好在r-10^(-5)和r+10^(-5)(这样可以保证不会出现精度问题)。

输出格式:
对于每组数据,输出最优天平的宽度。如果无解,输出-1。你的输出和标准答案的绝对误差不应超过10^(-8)。

样例输入:

5
1.3
3
1
2
1
1.4
3
1
2
1
2.0
3
1
2
1
1.59
4
2
1
1
3
1.7143
4
1
2
3
5

样例输出:

-1
1.3333333333333335
1.6666666666666667
1.5833333333333335
1.7142857142857142

题目分析:(搜索)
天平的形态最后可以看成二叉树,所以问题转化成了我们有一堆点(点数还不超过6),要把这一堆点合成一颗树。我们可以用哈弗曼树的想法,每次把两个节点合成一个新的节点,最终只剩下一个节点,就是一组可行解,更新答案。

但是我们不知道每次要合并哪两个点,因为层数很少,所以可以暴力枚举。

这样这道题就做完了,我的做法灰常辣鸡,没有用什么高端的剪枝和搜索技巧。
想知道更多搜索基础知识和优化技巧,可以到其他神犇的博客学习。

注意事项:
在合并两个点的时候,有可能出现这样的情况:
搜索 【uva1354】 Mobile Computing (练习题7-7 天平难题)_第4张图片

红色是一个节点,蓝色是一个节点。
把这两个点合到一起的时候,右边的那只明显越界了啊,把左边那只给包起来了,所以我们可以发现,这个节点的左边界不仅仅跟左边的节点有关系,还跟右边的节点有关系,这种情况需要在合并的时候判断出来。

代码如下:(代码写的很辣鸡,勿喷)

#include
#include
using namespace std;
struct balance{
    double w,ls,rs;
    balance operator + (const balance c)
    {
        balance z;
        z.w=w+c.w;
        double l=c.w/(w+c.w);
        double r=w/(w+c.w);
        z.ls=max(l+ls,c.ls-r);
        z.rs=max(r+c.rs,rs-l);
        return z;
    }
}a[10];

double r,ans;
int s,T;

void dfs(int c)
{
    if(c==s)
    {
        double cs=a[1].ls+a[1].rs;
        if(cs<=r && cs>ans) ans=cs;
        return;
    }
    balance b[10],d[10];
    for(int i=1;i<=s-c+1;i++) b[i]=a[i];
    for(int i=1;i<=s-c+1;i++)
        for(int j=1;j<=s-c+1;j++)
    {
        if(i==j) continue;
        for(int k=1;k<=s-c+1;k++) a[k]=b[k];
        int top=0;
        for(int k=1;k<=s-c+1;k++)
            if(k!=i && k!=j) d[++top]=a[k];
        d[++top]=a[i]+a[j];
        for(int k=1;k<=top;k++) a[k]=d[k];
        dfs(c+1);
    }
}

int main()
{
    scanf("%d",&T);
while(T--)
{
    scanf("%lf%d",&r,&s);
    for(int i=1;i<=s;i++)
    {
        scanf("%lf",&a[i].w);
        a[i].ls=0;
        a[i].rs=0;
    }
    ans=-1;
    dfs(1);
    printf("%.10lf\n",ans);
}
    return 0;
}

你可能感兴趣的:(搜索)